开发者

Trouble Binding CommandParameter using XPath within HierarchicalDataTemplate

I am relatively new to WPF and I have run into a little problem. Using HierarchicalDataTemplates, I have successfully bound XML to a TreeView control. Each node renderers correctly (including the Label in the SubstepTemplate).

I can even get the bound Command in my ViewModel from the Button in the SubstepTemplate, but only if I enter a hardcoded value for the CommandParameter (e.g. 999). All attempts at binding to the commandID attribute in my XML have failed.

Here is what I have right now:

XML:

<root xmlns="">
  <step label="Step Label 1">
    <button label="Button Title 1A" commandID="701" />
    <button label="Button Title 1B" commandID="702" />
    <button label="Button Title 1C" commandID="703" />
  </step>
  <step label="Step Label 2">
    <button label="Button Title 2A" commandID="801" />
    <button label="Button Title 2B" commandID="802" />
  </step>
</root>

XAML:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SidePanel">

<HierarchicalDataTemplate
            x:Key="SubstepTemplate"
            DataType="button"
            ItemsSource="{Binding XPath=*}">
    <StackPanel Orientation="Horizontal">
        <Button Margin="2" Width="32" Height="32" Command="{Binding ElementName=MyTreeView, Path=DataCont开发者_如何学Cext.PluginCommand}" CommandParameter="{Binding XPath=@commandID}" />
        <Label VerticalAlignment="Center" Margin="8,0,0,0" Content="{Binding XPath=@label}" />
    </StackPanel>
</HierarchicalDataTemplate>

<HierarchicalDataTemplate
            x:Key="StepTemplate"
            DataType="step"
            ItemsSource="{Binding XPath=*}"
            ItemTemplate="{StaticResource SubstepTemplate}">
    <Expander Header="{Binding Mode=OneWay, XPath=@label}" HorizontalAlignment="Stretch">
    </Expander>
</HierarchicalDataTemplate>

<Style TargetType="{x:Type local:SidePanelControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:SidePanelControl}">
                <TreeView
                    Name="MyTreeView"
                    ItemsSource="{Binding XmlRoot}"
                    ItemTemplate="{StaticResource StepTemplate}"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    HorizontalAlignment="Stretch">
                </TreeView>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</ResourceDictionary>

ViewModel Snippet:

    public DelegateCommand<string> PluginCommand
    {
        get
        {
            if (pluginCommand == null)
            {
                pluginCommand = new DelegateCommand<string>(ExecPluginCommand, canExecPluginCommand);
            }
            return pluginCommand;
        }
    }

    public void ExecPluginCommand(string param)
    {
        LogMessage("In ExecPluginCommand, param = " + param);
    }

    public bool canExecPluginCommand(string param)
    {
        return true;
    }

What is the correct Binding expression that needs to go in the CommandParameter to get this to work? {Binding XPath=@commandID} doesn't seem to work, and I do not understand why not.


I found the problem. When an XPath is used as a CommandParameter binding, the templated DelegateCommand receives a parameter of type System.Xml.XmlNode, not string.

I was getting an exception in my Command when attempting to get the command data type

    void ICommand.Execute(object parameter)
    {
        TParam value = GetCommandDataType(parameter);
        Execute(value);
    }

because TypeConverter::CanConvertFrom did not know what to do with an argument of type System.Xml.XmlNode.

I was able to get the commandID value by testing explicitly for

    data is System.Xml.XmlNode

in GetCommandDataType(object data) and then returning the .Value member, i.e.

        else if (data is System.Xml.XmlNode)
        {
            System.Xml.XmlNode foo = (System.Xml.XmlNode)data;
            string fooVal = foo.Value;
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(string));
            result = (TParam)converter.ConvertFrom(fooVal);
        }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜