WPF交互命令涉及本地静态资源进行转换器参考。

4

我希望创建一个“可重复使用”的控件,它具有行为属性。正如此博客中所描述的。

为了进行数据绑定,数据必须进行转换。问题在于; 作为StaticResource,它只能看到顶层字典(app),而动态资源不起作用(“只能与依赖属性一起使用”)。

以下是简单(有效的) xaml (窗口):

<Window x:Class="testit.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter" >
                    <i:InvokeCommandAction Command="{Binding MouseEnterCommand}">
                        <i:InvokeCommandAction.CommandParameter>
                            <Binding Path="Name"
                                     Converter="{StaticResource SelectionConverter}"
                                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" />
                        </i:InvokeCommandAction.CommandParameter>
                    </i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </Grid>
</Window>

应用:

<Application x:Class="testit.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:testit"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:SelectionConverter x:Key="SelectionConverter" />
    </Application.Resources>
</Application>

最后是视图模型:

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;

namespace testit
{
    class ViewModel : INotifyPropertyChanged
    {
        private string _data;
        private readonly DelegateCommand<string> _mouseEnterCommand = null;

        public ViewModel() {
            _data = "hello ";
            _mouseEnterCommand = new DelegateCommand<string>(
                (s) => {
                    var a = s ?? "world ";
                    Data += s;
                    return;
                });
        }

        public DelegateCommand<string> MouseEnterCommand => _mouseEnterCommand;

        public string Data {
            get { return _data; }
            set {
                if (value == _data) return;
                _data = value;
                OnPropertyChanged("Data");
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public class SelectionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if (value == null) return "";
            char[] charArray = ((string)value).ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
}

现在,正如所说的,“这个工作”。然而,它并没有做我想要的事情:它混乱了顶级资源字典。我希望将资源从“app.”中移除,并将其放在Grid下面(或者任何我使用的面板下面)。

<Grid.Resources>
    <local:SelectionConverter x:Key="SelectionConverter" />
</Grid.Resources>

编辑:如果我将上述行添加到窗口内的网格中,则编译时会抛出以下错误(该行和位置是指Converter =“{StaticResource SelectionConverter}”):

"'System.Windows.StaticResourceExtension'上提供的值引发了异常。'行号'13'和行位置'38'。"

内部异常如下:

找不到名为'SelectionConverter'的资源。资源名称区分大小写。

为了清晰起见,这是修改后的window.xaml:

<Window x:Class="testit.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:testit"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseEnter" >
                    <i:InvokeCommandAction Command="{Binding MouseEnterCommand}">
                        <i:InvokeCommandAction.CommandParameter>
                            <Binding Path="Name"
                                     Converter="{StaticResource SelectionConverter}"
                                     RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" />
                        </i:InvokeCommandAction.CommandParameter>
                    </i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Rectangle>
        <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Grid.Resources>
            <local:SelectionConverter x:Key="SelectionConverter" />
        </Grid.Resources>
    </Grid>
</Window>

如果定义网格的控件是使用它的控件的父级,则我认为应该可以工作。 - 15ee8f99-57ff-4f92-890c-b56153
@EdPlunkett 我们一定是有所误解,因为它肯定不起作用。 - paul23
1
尝试将Grid.Resources放在Grid的顶部,而不是底部。 StaticResource会在解析过程的早期解析资源。 - 15ee8f99-57ff-4f92-890c-b56153
1个回答

3
StaticResource 标记扩展在调用 ProvideValue 时立即解析资源:

该资源的查找行为 类似于加载时查找,将查找当前 XAML 页面标记中先前加载的资源

如果 Grid.ResourcesGrid 的内容之后定义,则在解析 Grid 的内容时这些资源尚未被 "先前加载"。因此,请将资源放置在网格的顶部,以便在使用它之前定义其中的任何内容:
<Grid>
    <Grid.Resources>
        <local:SelectionConverter x:Key="SelectionConverter" />
    </Grid.Resources>

    <Rectangle x:Name="blah" Fill="Yellow" Stroke="Black" Width="100" Height="100">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseEnter" >
                <i:InvokeCommandAction Command="{Binding MouseEnterCommand}">
                    <i:InvokeCommandAction.CommandParameter>
                        <Binding Path="Name"
                                 Converter="{StaticResource SelectionConverter}"
                                 RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=Rectangle}" />
                    </i:InvokeCommandAction.CommandParameter>
                </i:InvokeCommandAction>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Rectangle>
    <TextBlock x:Name="namefield" Text="{Binding Data}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>

如果您能使用DynamicResource,那就没问题了,但是您发现由于某些原因,您无法使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接