C# 使用来自资源的控制
我尝试在我的应用程序中使用MVVM,因为它使事情变得更简单。因此,我的菜单项是一个数据类,绑定到一个具有自定义样式的按钮。该样式实际上绑定了底层数据 问题是,这些菜单项可以选择性地包含其他内容,如果不需要,可以将这些内容设置为折叠。到目前为止,这工作还不错,但是切换到MVVM会带来一些问题。我需要在某处定义附加内容,并以编程方式将其附加到菜单项 用代码进行设计是一种糟糕的方法。所以我想到了使用WPFs资源系统。我尝试将内容插入到有效的资源中。我可以按原样指定控件 但是当我尝试通过FindResource方法加载它时,它什么也找不到。我把它放在不同的地方,在不同的状态调用代码窗口构造函数,加载事件。。。但它在任何地方都找不到这种控制 我尝试了Application.Current.Resources[…],Application.Current.FindResource。。。窗口类也是如此。它总是出现ResourceReferenceKeyNotFoundException 此外,当放入资源文件时,它会给我一个解析异常,表示我不能在资源对象上使用x:Name。所以我基本上不能使用整个系统,因为我需要名称来绑定控件子元素之间的内容 这可能吗?是否打算这样使用?有没有更好的方法来实现这一点?这也是我不了解WPF设计原则的地方 PS:我尝试使用页面和资源作为.xaml文件的编译选项 这就是控制:C# 使用来自资源的控制,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我尝试在我的应用程序中使用MVVM,因为它使事情变得更简单。因此,我的菜单项是一个数据类,绑定到一个具有自定义样式的按钮。该样式实际上绑定了底层数据 问题是,这些菜单项可以选择性地包含其他内容,如果不需要,可以将这些内容设置为折叠。到目前为止,这工作还不错,但是切换到MVVM会带来一些问题。我需要在某处定义附加内容,并以编程方式将其附加到菜单项 用代码进行设计是一种糟糕的方法。所以我想到了使用WPFs资源系统。我尝试将内容插入到有效的资源中。我可以按原样指定控件 但是当我尝试通过FindReso
<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>
如果要在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"},
}
}
};
}
}
显示此菜单只需将菜单绑定到菜单项并指定一个HierarchicalDataTemplate,以便它知道如何绘制它们:
<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>
结果:
在这个特定的示例中,我将其硬编码为一个图像,并假设内容始终是一个字符串,但使用DataTemplate,您可以将内容设置为您想要的任何类,还可以指定每个类的显示方式。不,这不是正确的方法。您尝试使用FindResource和Application.Current.Resources的事实表明您仍在使用代码隐藏,而这不是MVVM。回答这个问题几乎是不可能的,因为您发布的代码似乎与您的描述不匹配。您谈论的是一个具有自定义内容的菜单,而您提供的XAML是一个在网格上带有标签的StackPanel。你到底想做什么?问题不在于菜单。菜单不错,风格也不错。如果我使用INotifyChangedProperty添加此菜单项的仅属性实例,它将正确显示该项。但是MVVM不是让您绑定一组项,然后自动从模型中创建视图吗?在本例中,菜单项就是模型。所以我用代码创建这些菜单项,因为它应该是动态的。我想添加到这个控件中的内容应该在某个地方声明,因为如果用代码创建这个控件的话,需要做很多工作。所以我必须加载它。谢谢你的详细回答。我想到目前为止我是对的。毕竟它确实是这样工作的。我在这里的特殊问题是,我没有一个图标作为内容,而是一个控件的整个层次结构。我在原始帖子中发布的内容——这是一种内容。但是,在代码中声明这一点是一件非常麻烦的工作,而且极不灵活。我想像XAML中的任何视图一样声明它,将其加载到DemoViewModel中,向该控件层次结构的特定元素添加绑定,然后将其设置为一个菜单项的内容。但正如前面提到的:我不能从参考资料中加载它。那很好,只需将所有内容放在DataTemplate中,并用自定义类在视图模型中表示它。或者,将其放在ControlTemplate中,并使用DataTrigger将其设置为MenuItem的模板。无论哪种方式,您都不必直接在代码隐藏或视图模型中创建视图控件或访问资源。
<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>