简体   繁体   中英

WPF Databinding to XAML

I'm currently trying to bind the enable property of two buttons to a single object declared in code behind but I can't seem to get it to work. My code so far is:

XAML:

    <UserControl x:Class="TestApp.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:local="clr-namespace:TestApp"
    mc:Ignorable="d">

     <Button  Name="AddButton" Background="DarkBlue" Foreground="LightGray" BorderBrush="LightGray" 
       BorderThickness="2" Content="+"
                 Click="AddPopup" ToolTip="Add Content" IsEnabled="{Binding User}"/>

     <Button ToolTip="Save" Name="SaveButton" Click="Connect" Background="DarkBlue" 
        Foreground="LightGray" 
                BorderBrush="LightGray" BorderThickness="2" IsEnabled="{Binding User}">
            <Image Source="/Resources/save.png"/>
        </Button>

C#:

public partial class MainWindow : UserControl
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        StartWork();
        MainBackgroundWork();
        EndWork();
    }

    private void StartWork(){
       //other code here
       User = true;
    }   
    
    private void EndWork(){
       //other code here
       User = false;
    } 

    private bool _User; 
    public bool User { get { return _User; } set { _User = value; EditOrNotChanged(); } }

    public event PropertyChangedEventHandler PropertyChangedContent;

    protected void EditOrNotChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChangedContent?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

StartWork() enables both buttons but EndWork() doesn't seem to disable them.

I've gone through a number of tutorials but can't seem to identify what's wrong. Any help would be appreciated.

Thanks.

StartWork() enables both buttons but EndWork() doesn't seem to disable them

Based on what do you make that claim? Because the code you posted will complete both calls before ever even showing the window to the user. How would they even tell that the enabled-state of either button has changed? In any case…

The issue most closely related to your stated concern is that while the data context is the window object, that object does not implement INotifyPropertyChanged . It has an event it raises, but a) that event is not called PropertyChanged , and b) even if it were, without the interface being specified in the declaration, the framework would never bother to look for the event.

The following is a little closer to correct, but importantly would in theory address the specific issue of data binding:

public partial class MainWindow : UserControl, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        StartWork();
        MainBackgroundWork();
        EndWork();
    }

    private void StartWork(){
       //other code here
       User = true;
    }   
    
    private void EndWork(){
       //other code here
       User = false;
    } 

    private bool _User; 
    public bool User { get { return _User; } set { _User = value; EditOrNotChanged(); } }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void EditOrNotChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Note that the above doesn't fix other serious problems with the code:

  • A UserControl should never set its own DataContext . That context is for client code to set, only .
  • Properties declared on a UserControl should be implemented as dependency properties, not INotifyPropertyChanged properties. If you want the latter, you can create a separate view model object that implements INotifyPropertyChanged , and then use that view model object for the data context of one or more elements inside the UserControl (but never the UserControl itself…see previous point).
  • You should not be performing any sort of long-running operation (eg something that would benefit from changed the enabled-state of any controls) in a constructor . Limit the constructor only to things that are purely required for initialization. You can subscribe to the Loaded event, and in that handler start any sort of post-initialization work that might be time-consuming.
  • You should not be blocking the code while doing any long-running operation. It would be much better to execute that code in an async method, using await Task.Run(...) for the long-running operation itself.

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