简体   繁体   中英

Unable to tie a Object Property to a WPF MenuItem using Data Binding

I'm trying to set a property of an object when a specific MenuItem is chosen. For example, If the 'Start' MenuItem is chosen, the property should be set to TRUE. If a different MenuItem is chosen such as 'Stop', the property should be set to FALSE. I also set up a Command binding to start a separate window when one of the MenuItems is chosen. The command binding works and starts the separate window when the "Start" MenuItem is chosen. However, the property does not go to TRUE when "Start" is chosen.

This is what I have so far:

<Window x:Class="ServerWindows.ServerMenuBar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:server="clr-namespace:ServerWindows;assembly=ServerWindows"
    Title="Server Window" Height="65" Width="650" MaxWidth="650" MaxHeight="65" MinHeight="65" MinWidth="650" ResizeMode="NoResize">
    <Window.Resources>
        <Style x:Key="ServerStarted" TargetType="MenuItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding server:ServerMenuCommands.ServerStarted}" Value="true">
                    <Setter Property="Tag" Value="true"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <Style x:Key="ServerStopped" TargetType="MenuItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding server:ServerMenuCommands.ServerStarted}" Value="false">
                    <Setter Property="Tag" Value="false"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <Grid>
        <MenuItem FontSize="14" Header="Start" Command="server:ServerMenuCommands.OpenPuttyDisplayCommand" Style="{StaticResource ServerStarted}"/>
        <MenuItem FontSize="14" Header="Stop" Style="{StaticResource ServerStopped}"/>
    </Grid>
</Window>

The class definition combines the data property with the command bindings in a static class as such:

public static class ServerMenuCommands
{
    public static bool ServerStarted
    {
        get;
        set;
    }

    public static readonly RoutedUICommand OpenPuttyDisplayCommand = new RoutedUICommand("Open Putty Display", "PUTTY_DISPLAY", typeof(ServerMenuCommands));
}

Finally, the use of the property is done in the window started by the Command Binding:

if (ServerMenuCommands.ServerStarted)
{
   puttyText.AppendText("\n\rServer STARTED");
   puttyText.ScrollToEnd();
}
else
{
   puttyText.AppendText("\n\rServer STOPPED");
   puttyText.ScrollToEnd();
}

Again. I just want to set the above property so I can emit a notification to the user the choice of MenuItem "Start" or "Stop" by updating the separate window started by the Command Binding.

Thanks in advance for any help on this.

EDIT

Well. After trying the answer below with several other tweaks to what is outlined below, I am unable to get what I need working. It seems that maybe there is a misunderstanding of what I want to accomplish. I want to set a property of a static object based on a choice of a particular menu item control. It seems that examples I see work the other way around. Set a property of a control based on the value of a Property (field) of an object. That is why I did not create an event in my static class. I don't want to send a PropertyChanged event anywhere. I want to set the field to a value (True or False). Thanks for the potential solution to my problem. It looks like I'll just assign Click callbacks to the Menu Items and set the object Property that way.

Edit:Edit I am finally able to get this working based on the edited answer below. The key changes for me was to add the Command Bindings in the XAML and call the command method that changes the static property. Also key was the static event and tying it to the static property setter and then tying it to the Trigger in the XAML. It's all good all around!

EDIT:

I have been unable to make two-way(or at least proper one-way) binding to the static property on the static class. Seems, that it is impossible.

The only way I can propose is to make the class non-static (to allow its instantiation) and bind to its static properties using the resource instance:

ServerMenuCommands and code-behind:

public class ServerMenuCommands
{
    public static event EventHandler ServerStartedChanged;

    private static Boolean _ServerStarted;
    public static Boolean ServerStarted
    {
        get
        { 
            return _ServerStarted; 
        }
        set
        {
            if (value != _ServerStarted)
            {
                _ServerStarted = value;

                if (ServerStartedChanged != null)
                    ServerStartedChanged(typeof(ServerMenuCommands), EventArgs.Empty);
            }
        }
    }

    public static readonly RoutedUICommand OpenPuttyDisplayCommand = new RoutedUICommand("Open Putty Display", "PUTTY_DISPLAY", typeof(ServerMenuCommands));
}

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        ServerMenuCommands.ServerStarted = !ServerMenuCommands.ServerStarted;
    }
}

XAML :

<Window.CommandBindings>
    <CommandBinding Command="server:ServerMenuCommands.OpenPuttyDisplayCommand" Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<Window.Resources>
    <server:ServerMenuCommands x:Key="serverResource"/>
    <Style x:Key="ServerStarted" TargetType="MenuItem">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Source={StaticResource serverResource}, Path=ServerStarted}" Value="true">
                <Setter Property="Background" Value="Green"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
    <Style x:Key="ServerStopped" TargetType="MenuItem">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Source={StaticResource serverResource}, Path=ServerStarted}" Value="false">
                <Setter Property="Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <MenuItem Header="Start" Command="server:ServerMenuCommands.OpenPuttyDisplayCommand" Style="{StaticResource ServerStarted}"/>
    <MenuItem Grid.Column="1" Header="Stop" Style="{StaticResource ServerStopped}"/>
    <TextBox Grid.Column="2">
        <TextBox.Text>
            <Binding Source="{StaticResource serverResource}" Path="ServerStarted"/>
        </TextBox.Text>
    </TextBox>
</Grid>

This works and changes the values(backgrounds) with each OpenPuttyDisplayCommand execution.

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