Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Binding commands in styles and/or data templates (MVVM)?

Here's the very quick and simplified explanation of my situation. I have defined a style for Hyperlink controls and they have Command property binded to the command defined in a ViewModel class (simplified):

<Window.Resources>
  ...
  <Style x:Key="hyperlinkStyle" TargetType="Hyperlink">
    ...
    <Setter Property="Command" Value="{Binding Path=OpenHyperlinkCommand}" />
    ...
  </Style>
  ...
</Window.Resources>

Next, I created a content control in the window I am designing. It has a data template defined, written in the window resources. Inside that data template, I added some hyperlinks and I set those hyperlinks to use the previously defined style.

The window looks like this (simplified):

<Window>
  ...
  <ContentControl 
      ...
      ContentTemplate="{StaticResource myDataTemplate}" />
  ...
</Window>

The data template looks like this (simplified):

<Window.Resources>
  ...
  <DataTemplate x:Key="myDataTemplate DataType="{x:Type my:MyType}">
    ...
    <TextBlock>
      <Hyperlink 
          Style="{StaticResource hyperlinkStyle}" 
          CommandParameter="{Binding Path=Uri1}">
        <TextBlock Text="{Binding Path=Uri1}" />
      </Hyperlink>
    </TextBlock>
    ...
    <TextBlock>
      <Hyperlink 
          Style="{StaticResource hyperlinkStyle}" 
          CommandParameter="{Binding Path=Uri2}">
        <TextBlock Text="{Binding Path=Uri2}" />
      </Hyperlink>
    </TextBlock>
    ...
  </DataTemplate>
  ...
</Window.Resources>

The binding to the OpenHyperlinkCommand in the style doesn't work because the ViewModel of the window bound to it contains this command, but the DataTemplate is bound to the MyType objects, which do not contain this command (nor should).

How should I make this binding work? Two questions:

  1. Here's my proposal: I named my window x:Name="myWindow", and changed the binding of the command inside the style to this:

    <Setter Property="Command" Value="{Binding ElementName=myWindow Path=DataContext.OpenHyperlinkCommand}" />
    

    This works, but it looks so dirty. Am I doing this wrong? Is there a better way, more MVVM-like? This is fragile because I am setting specific element name inside a style!

  2. Is it a good practice to write the command bindings inside of a style in the first place? If not, what is the alternative? What if I developed a complex UserControl, how would I set commands to components somewhere deep inside its logical tree?

Thanks for all the help!

like image 338
Boris Avatar asked Apr 12 '11 22:04

Boris


People also ask

What is command binding in WPF?

The CommandBinding associates the Open command with Executed and CanExecute handlers. XAML Copy.

What is style in WPF?

Styles provide us the flexibility to set some properties of an object and reuse these specific settings across multiple objects for a consistent look. In styles, you can set only the existing properties of an object such as Height, Width, Font size, etc. Only default behavior of a control can be specified.


1 Answers

  1. An alternative syntax would use RelativeSource

    <Setter Property="Command" Value="{Binding DataContext.OpenHyperlinkCommand, RelativeSource={Relative Source AncestorType={x:Type Window}}}">

  2. I don't see anything wrong with writing command bindings in a style

like image 99
Rachel Avatar answered Nov 16 '22 01:11

Rachel