Use an attached Property to set Resources/Styles

Suppose that you have a UserControl and you want to merge some resources (which defines the styles, template and etc). 

 

Suppose again that we cannot add the style to Application or Window, whereas you might conflict with styles that may be used by other part of the application (typical e.g. when the shell is designed by some developers but individual view is taken care by some other developers).

 

You may do something like this :

 

 

<UserControl x:Class="MyView"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             >
  
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/MyModule;component/Resource/Style/DarkStyles.xaml" />
        <ResourceDictionary Source="pack://application:,,,/MyModule;component/Resource/Style/Styles.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
    </UserControl.Resources>

</UserControl>
 

 

 

This sound OK, however, suppose there are many of them, and you might need to do the copy and paste more than once.. 

 

which sound OK at initial sight, but look at the possibility of a change, see rename to the styles, things get ugly with copy&paste.

 

 

Suppose that the UserControl may use one/a group of fixed styles, then it make sense to have some way that you can easily pick up the styles.

 

 

One things comes to us is the attached property. below is the impl which leverage the attachedProperty, which accepts a string (in Pack Uri format) to the target style.

 

here are the code.

 

 

 

namespace MyNamespace
{
  public class ResourceLoader
  {


    public static string GetResourcePackUri(DependencyObject obj)
    {
      return (string)obj.GetValue(ResourcePackUriProperty);
    }

    public static void SetResourcePackUri(DependencyObject obj, string value)
    {
      obj.SetValue(ResourcePackUriProperty, value);
    }

    // Using a DependencyProperty as the backing store for ResourcePackUri.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResourcePackUriProperty =
        DependencyProperty.RegisterAttached("ResourcePackUri", typeof(string), typeof(ResourceLoader), new UIPropertyMetadata(string.Empty, ResourcePackUriChanged));


    private static void ResourcePackUriChanged(object sender_, DependencyPropertyChangedEventArgs args)
    {
      //DependencyPropertyDescriptor dpDescriptor = DependencyPropertyDescriptor.FromName("ResourcePackUri", typeof(ResourceLoader), 
      if (sender_ == null) throw new ArgumentNullException("sender_");
      //DependencyPropertyDescriptor dpDescriptor = DependencyPropertyDescriptor.FromName("ResourcePackUri", typeof(ResourceLoader), sender_.GetType());
      //if (dpDescriptor != null)
      //{
      //}
      var dpObject = sender_ as DependencyObject;

      if (dpObject != null)
      {
        if (dpObject is UserControl)
        {
          var usercontrol = (UserControl)dpObject;
          var uriInString = (string)args.NewValue;
          var uriOld = (string)args.OldValue;
          if (!string.IsNullOrEmpty(uriInString))
          {
            Uri uri = new Uri(uriInString);
            ResourceDictionary resourceNew = new ResourceDictionary();
            resourceNew.Source = uri;

            if (!string.IsNullOrEmpty(uriOld))
            {
              var resourceOld = usercontrol.Resources.MergedDictionaries.FirstOrDefault<ResourceDictionary>(r => r.Source == new Uri(uriOld));
              if (resourceOld != null)
                usercontrol.Resources.MergedDictionaries.Remove(resourceOld);
            }
            usercontrol.Resources.MergedDictionaries.Add(resourceNew);
          }
          else
          {
            throw new ArgumentException("ResourcePackUri only accepts string values");
          }
        }
        else
        {
          // ??
          throw new ArgumentException("AttachedProperty ResourcePackUri is only applicable on UserControl");
        }
      }
    }

  }
}
 

 

 

after this, you may do this to add the attached property to the UserControl.

 

 

 

<UserControl x:Class="MyNamespace.MyView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:local="clr-namespace:MyNamespace"
             local:ResourceLoader.ResourcePackUri="pack://application:,,,/MyModule;component/Resource/Style/MergedStyles.xaml"
             >
</UserControl>
 

 

 

and if you look at the pack://application:,,,/MyModule;component/Resource/Style/MergeStyles.xaml, you will see something like this:

 

 

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="pack://application:,,,/MyModule;component/Resource/Style/DarkStyles.xaml"/>
    <ResourceDictionary Source="pack://application:,,,/MyModule;component/Resource/Style/Styles.xaml"  />
  </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
  
 

 

Follow this discussion, we mihgt looks into how to make use of the Custom Markup Extension to accomplish the same task.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值