我有一个自定义控件,我需要从GridView继承。 标准方式,适用于UserControl,
<UserControl.Resources>
<local:NodeToImageConverter x:Key="imageConverter" />
<local:ImageHeightConverter x:Key="imageHeightConverter" />
</UserControl.Resources>
它对我不起作用。 我真的想使用本地资源 - 不要把它们放得更高。 我尝试创建一个级别的类并为那里的资源声明一个依赖属性。但它不起作用:
public partial class CustomDetailsView2 : GridViewRes {
public CustomDetailsView2() {
InitializeComponent();
} // it is interesting that if i set a breakpoint here i see my resourses - 2 items
}
public class GridViewRes : GridView {
public static DependencyProperty ResourcesProperty = DependencyProperty.Register(
"Resources",
typeof(ResourceDictionary),
typeof(CustomDetailsView2),
new FrameworkPropertyMetadata() {
DefaultValue = new ResourceDictionary()
});
public ResourceDictionary Resources {
get { return (ResourceDictionary)GetValue(ResourcesProperty); }
set { SetValue(ResourcesProperty, value); }
}
}
这是xaml
<local:GridViewRes x:Class="Nexplorer.UIParts.CustomDetailsView2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Nexplorer.UIParts"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<local:GridViewRes.Resources>
<local:NodeToImageConverter x:Key="imageConverter" />
<local:ImageHeightConverter x:Key="imageHeightConverter" />
</local:GridViewRes.Resources>
i tried also attached property - with no success
<local:CustomProperties.Resources>
<local:NodeToImageConverter x:Key="imageConverter" />
<local:ImageHeightConverter x:Key="imageHeightConverter" />
</local:CustomProperties.Resources>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Stretch="Fill" HorizontalAlignment="Left">
<Image.Source>
<MultiBinding Converter="{StaticResource imageConverter}"> here i have a runtime "imageConverter resourse not found" exception...
<Binding Path="IconSize" ElementName="thisControl"/>
<Binding />
</MultiBinding>
</Image.Source>
</Image>
<TextBlock Grid.Column="1" Text="{Binding Path=DisplayName}" VerticalAlignment="Center" Margin="2 1 0 1"/>
<Grid.Height>
<Binding Path="IconSize" Converter="{StaticResource imageHeightConverter}" ElementName="thisControl" />
</Grid.Height>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Size">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DisplaySize}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Modified">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DisplayModifiedDateTime}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</local:GridViewRes>
如何在此xaml中声明资源?
答案 0 :(得分:4)
确定。删除所有代码并从头开始。
如果你正在使用WPF,你需要在古代UI框架中留下过去可能使用的所有传统方法,并理解并接受The WPF Mentality。
基本上,除非您想要创建特定于控件的功能,否则永远不会继承WPF UI元素(或控件)。使用Styles and Templates在WPF中实现更改任何UI元素(或其子元素)的可视外观。
这是你在WPF中的表现方式:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="TilesTemplate">
<ListView ItemsSource="{Binding Files}">
<ListView.Template>
<ControlTemplate TargetType="ListView">
<WrapPanel IsItemsHost="True" ItemWidth="200"/>
</ControlTemplate>
</ListView.Template>
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<Image DockPanel.Dock="Left" Height="32" Width="32" Margin="5"
Source="http://files.softicons.com/download/internet-icons/bremen-icons-by-pc.de/png/32/folder.png"/>
<StackPanel>
<TextBlock Text="{Binding Name}" FontWeight="Bold" TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding Length}" Foreground="Gray"/>
</StackPanel>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
<DataTemplate x:Key="DetailTemplate">
<ListView ItemsSource="{Binding Files}">
<ListView.View>
<GridView>
<GridViewColumn Header="File Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Size" DisplayMemberBinding="{Binding Length}"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</Window.Resources>
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<RadioButton Content="Tiles" IsChecked="{Binding TilesMode}"/>
<RadioButton Content="Details" IsChecked="{Binding DetailsMode}"/>
</StackPanel>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<!-- This DataTrigger will change the View Mode to Tiles -->
<DataTrigger Binding="{Binding TilesMode}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource TilesTemplate}"/>
</DataTrigger>
<!-- This DataTrigger will change the View Mode to Details -->
<DataTrigger Binding="{Binding DetailsMode}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource DetailTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DockPanel>
</Window>
代码背后:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ExplorerViewModel();
}
}
视图模型:
public class ExplorerViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private bool _detailsMode;
public bool DetailsMode
{
get { return _detailsMode; }
set
{
_detailsMode = value;
OnPropertyChanged();
}
}
private bool _tilesMode;
public bool TilesMode
{
get { return _tilesMode; }
set
{
_tilesMode = value;
OnPropertyChanged();
}
}
public ObservableCollection<FileInfo> Files { get; set; }
public ExplorerViewModel()
{
var path = @"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE";
Files = new ObservableCollection<FileInfo>(Directory.GetFiles(path).Select(x => new FileInfo(x)));
TilesMode = true;
}
}
结果:
请注意我如何使用ListView
之类的标准WPF UI元素以及上述链接中所述的DataTemplate
等概念。
请注意,这种方法非常简洁,因为它需要更少的代码,并且通过使用正确的DataBinding使UI与数据完全分离。
与传统的UI框架(例如winforms)相比,您无法自定义任何内容,并且您不得不使用默认内容,WPF采用了不同的方法。它没有太多“开箱即用”的UI,因为可定制性水平很高,您可以在任何时间轻松创建100%自定义UI(如此处所示)。
运行此示例时,请确保path
构造函数中的ExplorerViewModel
变量指向硬盘驱动器上的有效路径。
WPF Rocks。 - 只需将我的代码复制并粘贴到File -> New Project -> WPF Application
中,然后自行查看结果。
答案 1 :(得分:0)
实际上有一种简单的方法可以做到这一点。这是所有自动生成的UserControls和Windows使用的范例,但它不仅限于它们,你甚至可以在子类化时使用它。
看一下如何在代码和XAML中定义stock MainWindow
类 - 在创建新的WPF应用程序项目时为您自动生成的类。它在XAML中使用基类型(你会发现它以<Window x:Class="WpfApplication1.MainWindow">
而不是它的派生类型MainWindow开头。同样适用于你的GridView,只需使用它的基本类型,而不是本地:GridViewRes。然后,您可以使用其所有继承的属性,包括Resources,以及其他任何地方。唯一的限制是您不能将代码隐藏XAML中的值分配给您在派生类中新定义的属性,但我几乎无法想想一个有用的场景 - 你也可以在代码中做到这一点(当然,任何使用你的控件的人都可以在XAML中完成它,包括从GridView继承的属性)。
当然,正如已经说过的那样,应该仔细考虑他真的是否需要子类化WPF控件。它带来了一些问题,通常更清晰的解决方案是将其包装到UserControl中,并仅导出您想要与世界共享的少数属性。只是我的两分钱。