[WPF] RadioButton Context an ViewModel Property binden.



  • Morgen Leute,

    folgendes liegt vor:

    View:

    <Grid>
    		<HeaderedItemsControl ItemsSource="{Binding Tools}" Header="Toolbox" Foreground="White" >
    			<HeaderedItemsControl.ItemTemplate>
    				<DataTemplate>
    					<RadioButton GroupName="Tools" Template="{StaticResource RadioButtonTemplate}" />
    				</DataTemplate>
    			</HeaderedItemsControl.ItemTemplate>
    		</HeaderedItemsControl>	
    	</Grid>
    

    ViewModel:

    public class ToolBoxViewModel : WorkspaceViewModel
    	{
    		public ObservableCollection<Tool> Tools { get; private set; }
    		public Tool _selectedItem;
    		public Tool SelectedItem
    		{
    			get { return this._selectedItem; }
    			set
    			{
    				if (this._selectedItem != value)
    				{
    					this._selectedItem = value;
    					this.NotifyPropertyChanged("SelectedItem");
    				}
    			}
    		}
    
    		public ToolBoxViewModel()
    		{
    			this.Tools = this.CreateToolBoxElements();
    		}
    
    		private ObservableCollection<Tool> CreateToolBoxElements()
    		{
    			return new ObservableCollection<Tool>() { new Tool("/Images/Properties.png") { DisplayName = "CheckBox" },
    																											new Tool("") {DisplayName = "Button"}};
    		}
    	}
    

    Wie krieg ich es denn jetzt hin das aktuelle Checked Item an mein SelectedItem zu binden? Habs schon mit nem Command versucht, bzw mit nem ListItem drumherum aber alles erfolglos. Habt ihr einen Tipp?


  • Administrator

    Erstell ein ViewModel für die Tool Elemente und mach dort ein IsSelected Property rein. Die Verlinkung machst du dann hinten über die ViewModels. Wenn sich also ein IsSelected beim ToolViewModel auf true ändert, wird das IsSelected des bisherigen selektierten ToolViewModel auf false gesetzt und das SelectedItem des ToolBoxViewModel aktualisiert. Am besten kann dies wahrscheinlich gleich das ToolBoxViewModel machen. Also braucht jedes ToolViewModel eine Referenz auf das dazugehörige ToolBoxViewModel .

    Grüssli



  • Hmm das wäre ne Idee. Aber ich hab gerade gesehen das ich vergessen hab einen Wichtigen Fakt mit zur erläutern: Ich selektiere die RadioButtons in der View mit der Mouse und möchte das an das ViewModel propagieren, ich glaub dann funktioniert das mit deiner Lösung nicht mehr oder?


  • Administrator

    Ich seh das Problem nicht ganz. Du selektierst die RadioButton mit der Maus, dadurch verändert sich ja die Checked Property. Wenn du nun die Checked Property an die IsSelected Property des ToolViewModel bindest, sollte dies doch kein Problem machen. Oder verstehe ich dich falsch?

    Grüssli



  • Ja klar, hast Recht, ich werds mal probieren, danke.



  • Schau mal Dravere, wie gefällt dir die Lösung:

    ToolBoxViewModel

    private ObservableCollection<ToolViewModel> CreateToolBoxElements()
    		{
    			Tool t = new Tool("/Images/Properties.png") {DisplayName = "CheckBox" };
    			ToolViewModel tv = new ToolViewModel(t);
    			tv.SelectionChanged += this.OnSelectionChanged;
    
    			return new ObservableCollection<ToolViewModel>() { tv };
    		}
    
    		private void OnSelectionChanged(object sender, ToolSelectionChangedEventArgs e)
    		{
    
    			this.SelectedItem = e.ChangedTool;
    		}
    

    ToolViewModel:

    public class ToolViewModel : ObservableObject
    	{
    		private bool isSelected;
    		public bool IsSelected
    		{
    			get { return this.isSelected; }
    			set
    			{
    				if (this.isSelected != value)
    				{
    					this.isSelected = value;
    					this.NotifyPropertyChanged("IsSelected");
    					this.OnSelectionChanged();
    				}
    			}
    		}
    		public Tool Tool { get;private set; }
    		public event EventHandler<ToolSelectionChangedEventArgs> SelectionChanged;
    
    		public ToolViewModel(Tool t)
    		{
    			this.Tool = t;
    			this.IsSelected = false;
    		}
    
    		private void OnSelectionChanged()
    		{
    			EventHandler<ToolSelectionChangedEventArgs> h = this.SelectionChanged;
    
    			if (h != null)
    				h(this, new ToolSelectionChangedEventArgs() { ChangedTool = this.Tool});
    		}
    	}
    

    Dann brauch ich die nich bei jedem ToolViewModel die Referenz auf die ToolBoxViewModel mitschleppen.
    Natürlich ist das dann am RadioButton Two-Way gebindet.


  • Administrator

    Firefighter schrieb:

    Schau mal Dravere, wie gefällt dir die Lösung

    Mir gefallen daran nicht:
    1. Man muss viel mehr schreiben!
    -> ToolSelectionChangedEventArgs Klasse
    -> Entsprechender Code, welcher auf SelectionChanged reagiert.
    2. Die Sache ist fehleranfälliger!
    -> Du musst die Event-Handler entfernen, wenn ein ToolViewModel entfernt wird!

    Wenn du direkt eine Referenz behalten würdest, könntest du das folgende machen:

    class ToolViewModel
    {
      // ...
      private bool isSelected;
      private ToolBoxViewModel parent;
    
      // ...
      public bool IsSelected
      {
        get { return this.isSelected; }
        set
        {
          if(this.isSelected != value)
          {
            this.isSelected = value;
            this.parent.SelectedItem = this;
            // ... notify blabla
          }
        }
      }
    }
    

    SelectedItem hast du ja bereits in ToolBoxViewModel . Dort musst du nur noch das folgende ergänzen:

    public ToolViewModel selectedItem;
    public ToolViewModel SelectedItem
    {
      get { return this._selectedItem; }
      set
      {
        if (this._selectedItem != value)
        {
          if(this._selectedItem != null)
          {
            this._selectedItem.IsSelected = false;
          }
    
          this._selectedItem = value;
    
          if(this._selectedItem != null)
          {
            this._selectedItem.IsSelected = true;
          }
    
          this.NotifyPropertyChanged("SelectedItem");
        }
      }
    }
    

    Und übrigens:

    private void OnSelectionChanged()
    {
      EventHandler<ToolSelectionChangedEventArgs> h = this.SelectionChanged;
    
      if (h != null)
        h(this, new ToolSelectionChangedEventArgs() { ChangedTool = this.Tool});
    }
    

    ->

    private void OnSelectionChanged()
    {
      var h = this.SelectionChanged;
    //^^^
    
      if (h != null)
        h(this, new ToolSelectionChangedEventArgs() { ChangedTool = this.Tool});
        // und wäre ein vernünftiger Konstruktur hier nicht klüger?
    }
    

    😉

    Aber ich weiss nicht, kommt natürlich auch auf die Umgebung an. Ob du dabei bleiben willst, dass SelectedItem das Tool zurückgibt und nicht das ToolViewModel .
    Wieso willst du aber hier überhaupt Events verwenden? Klar ist Entkopplung sinnvoll, aber ist sie hier auch wirklich nötig? Eine niedrige Kopplung bedeutet meistens auch eine erhöhte Komplexität.

    Grüssli



  • Erdrückende Beweisführung 😃

    Und ich dachte meine Events wären was tolles, da hab ich natürlich voll vergessen das ich die Entfernen muss. Ich Dösbattel.

    Dann ist deine Lösung natürlich besser. Klare Sache.

    Du und dein var. 😃 Das kriegen wir vermutlich nich mehr raus wa ;):p


Log in to reply