WPF 自定义泛型用户控件后跨程序集继承用户控件的解决方案

自定义泛型用户控件:

<UserControl x:Class="ClassLibrary1.UcEumCmb"
             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:ClassLibrary1"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid DataContext="{Binding ElementName=parent}">
        <ComboBox Name="cmb2" SelectedItem="{Binding SelectedEnumValue}" />
    </Grid>
</UserControl>
    public abstract partial class UcEumCmb : UserControl
    {

    }

    /// <summary>
    /// UcEumCmb.xaml 的交互逻辑
    /// </summary>
    public class UcEumCmb<T> : UcEumCmb where T : struct
    {
        public UcEumCmb()
        {
            InitializeComponent();
           // this.LoadViewFromUri("/ClassLibrary1;component/UcEumCmb.xaml");
            foreach (Enum enumValue in Enum.GetValues(typeof(T)))
            {
                cmb2.Items.Add(enumValue);
            }
        }
        public T SelectedEnumValue
        {
            get { return (T)GetValue(SelectedEnumValueProperty); }
            set { SetValue(SelectedEnumValueProperty, value); }
        }

        public static readonly DependencyProperty SelectedEnumValueProperty =
            DependencyProperty.Register("SelectedEnumValue", typeof(T), typeof(UcEumCmb<T>), new FrameworkPropertyMetadata { BindsTwoWayByDefault = true });
    }

然后声明一个用户控件类,继承即可

 public class DayOfWeekSelectorExt2 : UcEumCmb<DayOfWeek> { }

以上参考了:

https://stackoverflow.com/questions/3811179/wpf-usercontrol-with-generic-code-behind

 

但是,当我们需要自定义泛型T用户控件的时候,大部分情况就是为了分离泛型T类库和用户控件类库之间的依赖,所以一般

DayOfWeekSelectorExt2 : UcEumCmb<DayOfWeek>

会放在主程序里去做

但是这会导致vs编辑器报错提示

不具有由 URI“/ClassLibrary1;component/uceumcmb.xaml”识别的资源。

直接运行也会报错

根据相关资料

1 https://blog.csdn.net/lishuangquan1987/article/details/123347719 (Wpf BUG:组件“XXX”不具有由 URI“XXX“识别的资源)

2 https://www.cnblogs.com/lindexi/p/16714348.html (dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承)

3 https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri

需要手动去load usercontrol对应的xaml解决方案如下:

 public static class Extensions
 {
     public static void LoadViewFromUri(this FrameworkElement userControl, string baseUri)
     {
         try
         {
             var resourceLocater = new Uri(baseUri, UriKind.Relative);
             var exprCa = (PackagePart)typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { resourceLocater });
             var stream = exprCa.GetStream();
             var uri = new Uri((Uri)typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater);
             var parserContext = new ParserContext
             {
                 BaseUri = uri
             };
             typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { stream, parserContext, userControl, true });
         }
         catch (Exception)
         {
             //log
         }
     }
 }
 public UcEumCmb()
 {
     //InitializeComponent();
     this.LoadViewFromUri("/ClassLibrary1;component/UcEumCmb.xaml");
     foreach (Enum enumValue in Enum.GetValues(typeof(T)))
     {
         cmb2.Items.Add(enumValue);
     }
 }

取消 InitializeComponent,改为手动load

项目编译运行均正常,

<StackPanel Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" >
    <TextBlock Text="{Binding DayOfWeek,StringFormat=You have selected {0}!}" />
    <uc:DayOfWeekSelectorExt2 SelectedEnumValue="{Binding DayOfWeek}" Margin="0,5,0,0" />
    <local:DayOfWeekSelectorExt3 SelectedEnumValue="{Binding DayOfWeek}" Margin="0,5,0,0" />
</StackPanel>

using ClassLibrary1;

namespace EnumSelector
{
	public class SomeViewModel	// TODO implement INotifyPropertyChanged to support all binding scenarios
	{
		public DayOfWeek DayOfWeek { get; set; }
	}

    public class DayOfWeekSelector : EnumComboBox<DayOfWeek> { }
    public class DayOfWeekSelectorExt : UserControl1<DayOfWeek> { }
    public class DayOfWeekSelectorExt3 : ClassLibrary1.UcEumCmb<DayOfWeek> {

  

 

posted on 2024-04-12 15:29  火星大能猫  阅读(45)  评论(0编辑  收藏  举报