简体   繁体   中英

How can I bind a WPF checkbox's IsChecked property to a boolean property of an object that is not a window

I found a lot of examples on how to bind the IsChecked property of a WPF checkbox to a boolean property, if both belong to the same Window class. I want to do a different thing:

I have the main window (excerpt):

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private readonly SoundFx _soundFx = new SoundFx();

    private void _StartNewGame()
    {
        _soundFx.GameStarted();
    }
}

Then I have the SoundFx class (excerpt):

public class SoundFx : DependencyObject
{
    public void GameStarted()
    {
        if (Enabled)
        {
            _PlayGameStartedSound();
        }
    }

    public bool Enabled
    {
        get { return (bool) GetValue(EnabledProperty); }
        set { SetValue(EnabledProperty, value); }
    }
    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.Register("Enabled", typeof(bool),
            typeof(SoundFx), new UIPropertyMetadata(false));

}

And I have the XAML (excerpt):

<Grid>
    <CheckBox IsChecked="{Binding ElementName=_soundFx, Path=Enabled}" x:Name="checkBoxSoundFx" Content="Sound FX" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom"/>
</Grid>

To be honest, I'm new to WPF and don't know exactly what I'm doing. What I'm trying to achieve is that the value of _soundFx.Enabled be changed when the user clicks on the checkBoxSoundFx element, without using any event handlers like Checked or Unchecked . This should be possible with data binding, shouldn't it?

First you need to create

 public SoundFx _soundFx  { get; set; }

as public property, because you cannot bind to private field

public MainWindow()
{
   InitializeComponent();
   _soundFx  = new SoundFx();
}

And from xaml you need to bind like:

<CheckBox IsChecked=
    "{Binding RelativeSource=
       {RelativeSource Mode=FindAncestor,AncestorType=Window},
       Path=_soundFx.Enabled}"}"
    x:Name="checkBoxSoundFx" 
    Content="Sound FX" 
    HorizontalAlignment="Right" 
    Margin="0,0,10,10" 
    VerticalAlignment="Bottom"/> 

You were close, you need a property to bind to and you need to set the DataContext if you didn't do it:

public partial class MainWindow
{
    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();
    }

    private readonly SoundFx _soundFx = new SoundFx();
    public SoundFx {get {return _soundFx;}}

    private void _StartNewGame()
    {
        _soundFx.GameStarted();
    }
}

You then need to bind to this property (and set the mode to OneWayToSource if you only need to set the property, never update the CheckBox according to the property value):

<Grid>
    <CheckBox IsChecked="{Binding Path=SoundFx.Enabled, Mode=OneWayToSource}" x:Name="checkBoxSoundFx" Content="Sound FX" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom"/>
</Grid>

By the way I'm not sure why you SoundFx is a DependencyObject and why your Enabled property is a DependencyProperty. A simple property would work aswell in this particular example.

DependencyProperties are useful when you want to set them in a Style or animate them with a Storyboard for example, you don't seem to be in this case. I think SoundFx should inherit DependencyObject and Enabled should be a simple property (This is an opinion I make knowing very little about your project though).

As I've managed to grow more experienced in WPF in the meantime, I would now say that my question itself was wrong. In order to avoid confusion in binding and unnecessary dependencies between view and model, I would now always prefer MVVM for cases like this.

Example: https://codereview.stackexchange.com/questions/124361/mvvm-am-i-doing-it-right

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM