简体   繁体   中英

How can I bind a command of a control in template to my ViewModel

Right, what I have is:

<Window x:Class="WpfGettingThingsDone.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    AllowsTransparency="True"
    Background="Transparent"
    WindowStyle="None"    
    Title="{Binding Title}" Height="300" Width="300">
    <Window.Resources>
        <ResourceDictionary>
            <Style x:Key="WindowBorderBackground" TargetType="{x:Type Border}">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
                            <GradientStop Color="#FF222222" Offset="0" />
                            <GradientStop Color="#FF222222" Offset="0.2" />
                            <GradientStop Color="#FFAAAAAA" Offset="0.6" />
                            <GradientStop Color="#FF222222" Offset="0.7" />
                            <GradientStop Color="#FFAAAAAA" Offset="0.9" />
                            <GradientStop Color="#FF222222" Offset="1" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Style>

            <Style x:Key="WindowHeaderedContent" TargetType="{x:Type HeaderedContentControl}">
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Border 
                                Background="Black"
                                BorderBrush="Black" 
                                BorderThickness="1"
                                CornerRadius="5,5,0,0"
                                Padding="4"
                                SnapsToDevicePixels="True"
                                >
                                <DockPanel>
                                    <Button DockPanel.Dock="Right" Command="{Binding Path=CloseCommand}">X</Button>
                                    <TextBlock
                                        FontSize="14"
                                        FontWeight="Bold"
                                        Foreground="White"
                                        HorizontalAlignment="Center"
                                        Text="{TemplateBinding Content}" />
                                </DockPanel>
                            </Border>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Window.Resources>

    <Border CornerRadius="5" Style="{StaticResource WindowBorderBackground}">
        <HeaderedContentControl Header="Current Contexts" 
                                Style="{StaticResource WindowHeaderedContent}" 
                                >
        </HeaderedContentControl>
    </Border>
</Window>

Basically draws a window with a pretty gradient background, using a HeaderedContentControl to create the title bar, which uses a HeaderTemplate to put the x button there.

Like so:

替代文字

However, as you can see, I've tried binding the command of the X (close) button to the CloseCommand in my ViewModel. Assuming my ViewModel is correct and that my lack of understanding of the WPF databinding stuff is the problem, what am I doing wrong? Can it not be done the way I'm trying?

(Note: For the purposes of this question I merged all resources in use by the window into the windows resource dictionary.)

Edit: Since Sam suggested my DataContext for my window isn't set, I'll clarify that it is set, but done in the code behind for App.Xaml when it creates the MainWindow.

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        MainWindow mainWindow = new MainWindow();            
        var viewModel = new MainWindowViewModel();

        viewModel.RequestClose += (s, ev) => mainWindow.Close();

        mainWindow.DataContext = viewModel;

        mainWindow.Show();
    }
}

Here's another attempt. Your button is in the DataTemplate for the Header of the HeaderedContentControl. This data template has a different data context to the parent control. It's data context is implicitly the value of the Header property. So to fix your problem you would need to do

<HeaderedContentControl Header="{Binding}" .../>

The empty {Binding} statement means "bind the property to the DataContext of this control".

Alternatively, you could use a RelativeSource binding where you set up the Command binding. Something like:

<Button DockPanel.Dock="Right" 
  Command="{Binding Path=DataContext.CloseCommand, RelativeSource={RelativeSource AncestorType={x:Type HeaderedContentControl}}}">...</Button>

In your Button you specify the Path of the binding, but not the data source. I think what you are missing is setting the DataContext of your window to be the ViewModel. You need something like

<Window ... DataContext="{StaticResource myViewModel}">
...

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