<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      KK的技術人生

      技術改變世界
      使用XamlReader.Load構建配置型自定義控件

      我們知道,用Xaml來設計控件UI相比使用后臺代碼來說要容易得多,而且借助Blend或VS2010界面設計器也更容易維護,不必為了修改一個小小的背景前景色要投身茫茫碼海中。但是Xaml相比代碼構造來說,失去了動態配置的靈活性,而且也很難用于復制出若干相同配置的控件實例。

      考慮下面這樣的情景:

      我們有一個圖表控件,我們使用Blend為這個圖表控件預先配置好了很多屬性使其展示效果最佳,然后我們希望應用程序其他用到圖表控件的地方也使用一樣的配置,但是允許其他地方自由選擇圖表的類型,例如以餅狀圖、柱狀圖或是條形圖展示。

      如果我們在代碼中使用工廠模式來構造這個圖表控件的話,那么我們通過讓使用者傳入配置參數的方式的方式來生成使用者期望的圖表,這倒是很容易,但如果這個控件的預配置過程是通過Xaml來完成的,那么要實現動態配置就麻煩很多了。而且由于Silverlight的UIElemnet沒有Clone方法,即使使用Xaml構建出了一個配置好了的實例,也很難復制出若干個相同配置的實例來。

      最近項目就遇到這樣的問題,最終我用XamlReader.Load方法動態加載Xaml資源文件的方式解決了這個問題。

      下面這個Xaml文件是一個包含DataGrid控件的Grid容器,這個DataGrid有兩列組成,但是數據綁定以及列名均允許動態配置。

      <Grid 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
          xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" 
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
          mc:Ignorable="d" d:DesignWidth="336" d:DesignHeight="208">
          <sdk:DataGrid x:Name="GridReport" ItemsSource="{Binding PagedItemsSource}" AutoGenerateColumns="False" IsReadOnly="True">
              <sdk:DataGrid.Columns>
                  <sdk:DataGridTextColumn Binding="{Binding Member}" Header="$(MemberHeader~BounceRate)"/>
                  <sdk:DataGridTextColumn Binding="{Binding Metrics[$(Metric~Count)]}" Header="$(MetricHeader~Visitors)"/>
              </sdk:DataGrid.Columns>
          </sdk:DataGrid>
          <sdk:DataPager x:Name="GridPager" DisplayMode="FirstLastPreviousNext" PageSize="5" Source="{Binding PagedItemsSource}"/>
      </Grid>

      在這里,我定義了一個簡單的參數替換規則,就是"$(ConfigKey~DefaultValue)",一旦遇到這樣的字符串,則認為此字符串為可配置字符串,如果使用者傳入該ConfigKey的配置,則使用配置項,否則使用默認值。如果Xaml中只是寫了"$(ConfigKey)”沒有默認值的話,那么表示此配置項必須由使用者傳入,否則拋出異常。

      之所以用$(~)這幾個特殊字符,是因為這幾個字符不會造成Blend Xaml解析器異常。

      那么怎么實例化這個Grid容器呢?我寫了一個XamlLoader輔助類來實現。

      /// <summary>
      /// 支持從某個Xaml資源中創建FrameworkElement。內建緩存。
      /// </summary>
      public static class XamlLoader
      {
          public static readonly string ContentResourcesBaseUri = "/Assets/ContentResources/";
          public static readonly string CurrentAssemblyName;
          private static Dictionary<string, string> _cache = new Dictionary<string, string>();
          private static Regex _parameterPattern = new Regex(@"\$\((?<parameter>\w+)~?(?<defValue>.*?)\)", RegexOptions.ExplicitCapture);
          private static object _shareLock = new object();
      
          static XamlLoader()
          {
              var assemblyName = new AssemblyName(Assembly.GetExecutingAssembly().FullName);
              CurrentAssemblyName = assemblyName.Name;
          }
          /// <summary>
          /// 從Xaml資源中實例化FrameworkElement對象。
          /// </summary>
          /// <typeparam name="T"></typeparam>
          /// <param name="key"></param>
          /// <param name="parameters"></param>
          /// <returns></returns>
          public static T CreateTemplatedFrameworkElement<T>(string key, Dictionary<string, string> parameters) where T : FrameworkElement
          {
              string xamlString = LoadXaml(key);
              // 搜索Xaml資源文件中的所有參數,使用parameters參數字典進行替換
              MatchCollection matches = _parameterPattern.Matches(xamlString);
              foreach (Match m in matches)
              {
                  string param = m.Groups["parameter"].Value;
                  string defValue = m.Groups["defValue"].Value;
                  if (parameters.ContainsKey(param))
                  {
                      xamlString = xamlString.Replace(m.Value, parameters[param]);
                  }
                  else if (!String.IsNullOrEmpty(defValue))
                  {
                      xamlString = xamlString.Replace(m.Value, defValue);
                  }
                  else
                  {
                      throw new InvalidOperationException(String.Format("Parameter {0} is not provided.", param));
                  }
              }
              return XamlReader.Load(xamlString) as T;
          }
      
          public static FrameworkElement CreateTemplatedFrameworkElement(string key, Dictionary<string, string> parameters)
          {
              return CreateTemplatedFrameworkElement<FrameworkElement>(key, parameters);
          }
      
          /// <summary>
          /// 讀取Xaml資源文件字符串。內建緩存。
          /// </summary>
          /// <param name="key"></param>
          /// <returns></returns>
          public static string LoadXaml(string key)
          {
              string xamlString;
              if (_cache.ContainsKey(key))
              {
                  xamlString = _cache[key];
              }
              else
              {
                  lock (_shareLock)
                  {
                      if (_cache.ContainsKey(key))
                      {
                          xamlString = _cache[key];
                      }
                      else
                      {
                          string resourceName = string.Format("{0};component{1}{2}.xaml", CurrentAssemblyName, ContentResourcesBaseUri, key);
                          Uri uri = new Uri(resourceName, UriKind.Relative);
                          StreamResourceInfo streamResourceInfo = Application.GetResourceStream(uri);
                          using (Stream resourceStream = streamResourceInfo.Stream)
                          {
                              using (StreamReader streamReader = new StreamReader(resourceStream))
                              {
                                  xamlString = streamReader.ReadToEnd();
                                  if (!String.IsNullOrEmpty(xamlString))
                                  {
                                      _cache[key] = xamlString;
                                  }
                              }
                          }
                      }
                  }
              }
              return xamlString;
          }
      }

      實例化的過程就變得很容易了,直接傳入模板控件所在資源文件的名稱以及一個字典配置對象即可。

      XamlLoader.CreateTemplatedFrameworkElement("DataGridTemplate",
          new Dictionary<string, string>
          {
              {"MemberHeader","視頻名稱"},
              {"MetricHeader","訪問人數"},
          });

      XamlReader.Load加載本程序集內自定義控件失敗的問題

      期間遇到一個很奇怪的問題,通過上述這種方法實例化一個定義在同一個程序集下的自定義控件卻拋出AG_E_UNKNOWN_ERROR的XamlParseException。

      <SlApp:MyControl 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:SlApp="clr-namespace:SlApp;" />

      后來總算找到問題所在。平常當我們在UserControl中用到一個自定義控件的時候,需要添加命名空間,命令空間的格式為:

      clr-namespace:CustomNamespace;assembly=CustomAssemblyName

      如果控件是在當前程序集下定義的,那么后面的assembly部分就可以省略,但是使用XamlLoader.Load方法加載時這一部分卻不能省去,否則就會拋出剛才提到的異常。

      正確的寫法應該是:

      <SlApp:MyControl 
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:SlApp="clr-namespace:SlApp;assembly=SlApp" />

       

      ——Kevin Yang

      posted on 2010-09-06 13:00  KK2038  閱讀(3935)  評論(1)    收藏  舉報

      主站蜘蛛池模板: 久久久久久综合网天天| 亚洲一区二区av偷偷| 毛片无遮挡高清免费| 亚洲色欲色欲www| 国产午夜精品福利免费不| 香蕉久久夜色精品国产成人| 午夜福利在线观看成人| 多伦县| 日韩人妻不卡一区二区三区| 天堂中文8资源在线8| 国产在线观看免费观看| 男女性高爱潮免费网站| 国产精品一区二区三区卡| 国产精品视频一区二区亚瑟| 福利一区二区在线视频| 成人免费在线播放av| 国产高清在线男人的天堂| 久久综合88熟人妻| 国产自拍在线一区二区三区| 67194熟妇在线观看线路| 婷婷亚洲综合五月天小说| 中文字幕国产精品第一页| 亚洲男人精品青春的天堂| 久久香蕉国产线看观看猫咪av| 国产熟睡乱子伦视频在线播放| 亚洲精品成人一二三专区| 国产美女自慰在线观看| 午夜av高清在线观看| 亚洲区综合区小说区激情区| 国产成人精品午夜2022 | 花莲市| 久久精品国产大片免费观看| 日韩人妻一区中文字幕| 隔壁老王国产在线精品| 亚洲天堂av免费在线看| 国产91成人亚洲综合在线| 最近中文字幕完整版2019| 这里只有精品免费视频 | 国产精品普通话国语对白露脸| 双牌县| 无码人妻av免费一区二区三区|