使用资源控制

时间:2015-09-22 22:41:50

标签: c# wpf xaml mvvm

我尝试将MVVM用于我的应用程序,因为它使事情变得更容易。所以我的菜单项是绑定到具有自定义样式的按钮的数据类(该样式实际上绑定了基础数据)。

事情是这些菜单项可以选择性地添加其他内容,如果不需要,可以设置为Collapsed。到目前为止,这种方法非常好,但是切换到MVVM会带来一些问题。我需要在某处定义附加内容,并以编程方式将其附加到菜单项。

代码中的设计工作是一种糟糕的方法。所以我想到了使用WPF资源系统。我尝试将内容插入到有效的资源中。我可以按原样指定控件。

但是当我尝试通过FindResource() - 方法加载它时,它找不到任何东西。我把它放到不同的地方,并在不同的状态调用代码(Window构造函数,Loaded-event,...)但是它无处可以找到这个控件。

我尝试使用Application.Current.Resources[...]Application.Current.FindResource(...)以及与Window类相同的操作。它总是出现ResourceReferenceKeyNotFoundException

此外,当放入资源文件时,它给我一个解析异常,表示我不能在资源对象上使用x:Name。所以我基本上不能使用整个系统,因为我需要名称才能在该控件的子元素之间绑定东西。

这甚至可能吗?它是否打算以这种方式使用?有没有更好的方法来实现这一目标?再一次,我没有得到WPF的设计原则......

PS:我尝试使用 Page Resource 作为.xaml文件的编译选项。

那是控件:

<views:AnimatedStackPanel x:Key="LiftMenuAnalyzeContent" HorizontalAlignment="Stretch" Orientation="Vertical" >
<views:AnimatedStackPanel.Children>
    <StackPanel x:Name="PaneAnalysisStep" Orientation="Horizontal" HorizontalAlignment="Center">
        <shared:Triangle Width="20" Height="24" ApexSide="Left"
                                            Fill="#ff8000" />
        <Border HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="#ff8000"
                                BorderBrush="#ff8000" BorderThickness="0" Padding="4">
            <TextBlock x:Name="TxtAnalysisStep" Text="Analyzing" />
        </Border>
        <shared:Triangle Width="20" Height="24" ApexSide="Right"
                                            Fill="#ff8000" />
    </StackPanel>

    <Grid x:Name="GridAnalysisInfo" HorizontalAlignment="Center" VerticalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30" />
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="50" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="27" />
            <RowDefinition Height="27" />
            <RowDefinition Height="27" />
        </Grid.RowDefinitions>

        <Label x:Name="LblObjectsFound" Grid.Row="1" Grid.Column="0"
                                Content="0" />
        <Label Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left"
                                Content="Targets" />
        <Label x:Name="LblIssuesFound" Grid.Row="2" Grid.Column="0"
                                Content="0" />
        <Label Grid.Row="2" Grid.Column="2" HorizontalAlignment="Left"
                                Content="Issues" />
        <Label x:Name="LblErrorsFound" Grid.Row="3" Grid.Column="0"
                                Content="0" />
        <Label Grid.Row="3" Grid.Column="2" HorizontalAlignment="Left"
                                Content="Errors" />
    </Grid>

    <TextBlock Margin="0,5,0,0" FontWeight="Bold"
                                Text="Not possible." TextAlignment="Center" TextWrapping="Wrap" />
</views:AnimatedStackPanel.Children>

1 个答案:

答案 0 :(得分:0)

如果要在MVVM中创建动态菜单,则需要首先为包含标题的每个菜单项声明一个视图模型,为动态内容指定一个字段(稍后详细介绍)和任何列表子菜单项:

public class MenuItemViewModel : ViewModelBase
{
    public string Header {get; set;}
    public object Content {get; set;}
    public MenuItemViewModel[] Children { get; set; }
}

然后您的视图模型需要创建这些结构的树:

public class DemoViewModel : ViewModelBase
{
    public MenuItemViewModel[] MenuItems {get; set;}

    public DemoViewModel()
    {
        this.MenuItems = new MenuItemViewModel[]
        {
            new MenuItemViewModel{
                Header = "File", Content="icon.png",
                Children = new MenuItemViewModel[]
                {
                    new MenuItemViewModel{Header="Open", Content="icon.png"},
                    new MenuItemViewModel{Header="Save", Content="icon.png"},
                    new MenuItemViewModel{Header="Close", Content="icon.png"},
                }
            },
            new MenuItemViewModel{
                Header = "Edit", Content="icon.png",
                Children = new MenuItemViewModel[]
                {
                    new MenuItemViewModel{Header="Cut", Content="icon.png"},
                    new MenuItemViewModel{Header="Copy", Content="icon.png"},
                    new MenuItemViewModel{Header="Paste", Content="icon.png"},
                }
            }
        };
    }
}

显示此菜单只需将Menu绑定到MenuItems并指定HeirarchicalDataTemplate,以便它知道如何绘制它们:

    <Menu ItemsSource="{Binding MenuItems}" DockPanel.Dock="Top">
        <Menu.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Children}">
                <ContentPresenter Content="{Binding Header}" />
            </HierarchicalDataTemplate>
        </Menu.Resources>
    </Menu>

结果:

enter image description here

在此示例中,我明确地让ContentPresenter显示Header属性中的内容,但您可以将其覆盖到您想要的任何内容。在我的原始视图模型中,我添加了Content属性并将它们全部设置为icon.png,我假设它是一种资源,我可以使用带有BitmapImage的图像来显示它源:

            <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Header}" />
                    <Image Width="16" Height="16">
                        <Image.Source>
                            <BitmapImage UriSource="{Binding Content}" />
                        </Image.Source>
                    </Image>
                </StackPanel>
            </HierarchicalDataTemplate>

结果:

enter image description here

在这个特定示例中,我将其硬编码为图像并假设Content将始终是一个字符串,但使用DataTemplating,您可以使Content任何您想要的类并指定每个应如何显示。