2012-04-06 15 views
22

Tôi có Thư viện điều khiển WPF đang được thêm vào ứng dụng biểu mẫu cửa sổ. Chúng tôi muốn cho phép các điều khiển có thể được bản địa hóa, tuy nhiên tôi không chắc chắn cách HOÀN TOÀN thực hiện điều này mà không cần sao chép mã. This is what I am doing now. Về cơ bản, trong ứng dụng biểu mẫu windows, trước khi ứng dụng chính khởi động, tôi đang tạo một App.xaml trong ứng dụng biểu mẫu (chứa liên kết đến tài nguyên của tôi cũng nằm trong ứng dụng biểu mẫu). Điều này hoạt động hoàn hảo cho thời gian chạy.Có cách nào để sử dụng StaticResource trong thư viện điều khiển WPF và có thể xem tại thời điểm thiết kế không?

Tuy nhiên, điều khiển người dùng của tôi tất cả đều có Content="{StaticResource SomeVariableName}", kết thúc để trống. Tôi có thể sửa lỗi này bằng cách sử dụng app.xaml và từ điển tài nguyên thích hợp trong thư viện điều khiển của tôi khớp với các từ điển trong ứng dụng biểu mẫu windows của tôi. Tuy nhiên, đây là mã trùng lặp.

Những điều tôi đã cố gắng vô ích:

  • Khởi tạo các App.xaml sống trong thư viện điều khiển người dùng từ bên trong ứng dụng các hình thức của tôi. Điều này không có tác dụng vì các URI đến tài nguyên của tôi đang tìm kiếm tài nguyên nhúng, không phải từ điển tài nguyên cục bộ của tôi (sau đó tôi có thể sao chép các tệp tài nguyên từ điều khiển đến vị trí thích hợp trong ứng dụng biểu mẫu của tôi trên bản dựng). Tôi có thể tận dụng DeferrableContent ở đây không? Không có nhiều trực tuyến như xa như tôi có thể tìm thấy trên thuộc tính này và làm thế nào nó nên được sử dụng, mặc dù.
  • Tôi muốn sử dụng các bản dựng bài đăng cho cả Ứng dụng và từ điển, tuy nhiên, ứng dụng instantiation là một tham chiếu tĩnh đến một App.xaml được biên dịch theo như tôi có thể nói. Vì vậy, App.xaml phải sống trong biểu mẫu ít nhất
    • Tôi đã cố gắng để có một App.xaml trùng lặp với một bài đăng xây dựng di chuyển Dictionary.xaml được cấp lại. Tôi thấy rằng một app.xaml trùng lặp là ok vì đó là động lực và bạn có thể không muốn dựa vào một từ kiểm soát anyway (mà vòng tròn trở lại và làm cho bạn tự hỏi nếu bạn nên sau đó có App.xaml trong sự kiểm soát tại Trừ khi bạn muốn cho phép mặc định sử dụng tài nguyên được nhúng ....) Điều đó quá thất bại khi nói rằng nó không thể tìm thấy tài nguyên mặc dù nó được đặt ở nơi mà URI nên trỏ đến. Các điểm mã decompiled để Uri resourceLocater = new Uri("/WindowsFormsApplication3;component/app.xaml", UriKind.Relative);

Vì vậy, Có cách nào để cho phép này để làm việc và có thời gian xem thiết kế của giá trị mặc định thành phần và tránh trùng lặp? Hoặc, là trùng lặp OK trong trường hợp này? Nếu mục con của viên đạn thứ 2 của tôi có vẻ ok (trùng lặp App.xaml với xây dựng các bản sao chép lại), làm cách nào để nó không tìm kiếm một mục mức thành phần, mà thay vào đó là một cấp độ tệp?

Câu hỏi cuối cùng (và tôi có thể đăng bài này một cách riêng biệt nếu cần) mà tôi vừa chú ý đến. App.xaml của tôi đang được tích hợp vào mã, vì vậy điều đó không cho phép tôi tạo Tài nguyên mới ngay lập tức. Có cách nào để làm điều này không?

Tùy chọn cuối cùng ... có thể là lựa chọn tốt nhất? - I plan on using Andre van Heerwaarde's code anyway, vì vậy tôi chỉ nên kiểm tra sự tồn tại của một tệp và thêm nó làm tài nguyên được hợp nhất khi đang di chuyển? Về cơ bản, có một App.xaml trong điều khiển người dùng của tôi liên kết đến một ResourceDictionary được nhúng mặc định. Và, sau đó có mã tìm kiếm các tài nguyên địa phương thích hợp khi đang di chuyển, có thể là các đường dẫn tệp tương đối? Nhược điểm duy nhất tôi thấy ở đây là mặc định không thể thay đổi trên bay ... mà tôi thậm chí có thể có cái nhìn đó ở một nơi cụ thể (sử dụng một số loại quy ước) và có được ưa thích hơn một trong xây dựng trong?

Ồ, và lý do tôi không muốn tài nguyên nhúng là để người dùng cuối có thể thêm/sửa đổi tài nguyên được bản địa hóa mới sau khi xây dựng được triển khai.

Tôi có thể thêm mã nếu nó sẽ giúp bạn hình dung điều này tốt hơn, chỉ cần cho tôi biết.

CẬP NHẬT

Tôi bây giờ chạy vào một vấn đề nữa với phong cách và không chỉ khoanh vùng.

Dưới đây là một ví dụ về một trong các nút bên trên một trong các điều khiển:

<Button Style="{StaticResource GrayButton}" 

Một số điều tôi càng cố gắng/suy nghĩ:

  • Tôi không thể tạo ra một App.xaml (mà sẽ không bao giờ được sử dụng) với ResourceDictionary được thiết lập như ApplicationDefinitions không được phép trong các dự án thư viện. Tôi có thể nhúng điều này vào tài nguyên của kiểm soát, nhưng sau đó sẽ luôn được ưu tiên hơn bất kỳ tài nguyên cấp ứng dụng nào và tôi mất khả năng tùy chỉnh.

Here is a connect case mà thực sự có vẻ như những gì tôi đang tìm kiếm, tuy nhiên nó không cung cấp bất kỳ giải pháp thực tế để

Các giải pháp này (ngoài top..which không hoạt động) mà tôi có thể nghĩ rằng có thể làm việc (và chưa thử) cũng có vẻ như rất nhiều công việc cho một cái gì đó mà tôi nghĩ sẽ đơn giản. Nhưng, tôi có thể tạo ra một số thuộc tính phụ thuộc trong điều khiển mà tôi có thể liên kết và sau đó cho phép những người đó được overriden bởi dự án sẽ sử dụng điều khiển. Như tôi đã nói, có vẻ như rất nhiều công việc cho một yêu cầu khá đơn giản :). Điều này thậm chí sẽ làm việc? Và quan trọng hơn, là có một giải pháp tốt hơn, đơn giản hơn mà tôi đang thiếu?

Trả lời

12

tôi đã chạy vào vấn đề này một lần, và tôi giải quyết nó bằng cách thả toàn bộ "Tài nguyên là đối tượng được lập chỉ mục bởi chủ chốt trong từ điển kinh điển" điều.

Ý tôi là, thực tế đơn giản về việc xác định tài nguyên trong một dự án và tham chiếu nó trong một dự án khác bằng "khóa" sẽ cung cấp cho người da trắng bất kỳ người lành mạnh nào. Tôi muốn tham chiếu mạnh mẽ.

Giải pháp của tôi cho vấn đề này là tạo ra một custom tool có thể chuyển đổi các file XAML nguồn lực của tôi đến các lớp học tĩnh với một tài sản cho mỗi tài nguyên:

Vì vậy MyResources.xaml:

<ResourceDictionary> 
    <SolidColorBrush x:Key="LightBrush" ... /> 
    <SolidColorBrush x:Key="DarkBrush" ... /> 
</ResourceDictionary> 

trở thành MyResources.xaml cs

public static class MyResources { 

    static MyResources() { 
    // load the xaml file and assign values to static properties 
    } 

    public static SolidColorBrush LightBrush { get; set; } 
    public static SolidColorBrush DarkBrush { get; set; } 

} 

Đối với tham khảo tài nguyên, bạn có thể sử dụng x:Static thay vì StaticResource:

<Border 
    Fill="{x:Static MyResources.LightBrush}" 
    BorderBrush="{x:Static MyResources.DarkBrush}" 
    ... /> 

Bây giờ, bạn đã tham khảo mạnh mẽ, tự động hoàn thành và kiểm tra thời gian biên dịch tài nguyên.

+1

+1 Đây là câu trả lời hay nhất mà tôi đã thấy cho đến thời điểm này. Bằng cách này, tôi có thể đặt mã nguồn tài nguyên của mình ở bất kỳ đâu và có nó hoạt động tuy nhiên tôi cần nó để hành động. Nhưng, làm thế nào điều này sẽ làm việc trong nhà thiết kế? Nó sẽ làm mới một trường hợp của MyResources và sử dụng các giá trị mặc định? –

+0

Theo như tôi nhớ, có. –

+0

+1 rực rỡ!Không bao giờ thậm chí vượt qua tâm trí của tôi để tiếp cận nó như thế này! – Dom

0

Tôi cũng gặp sự cố khi xử lý Chủ đề tạo kiểu và tài nguyên tĩnh có sẵn. Vì vậy, tôi tạo ra một thư viện độc lập mà về cơ bản không có gì ngoài các chủ đề được sử dụng tất cả lồng nhau như tài nguyên MERGED của câu hỏi được liên kết trước của bạn.

Sau đó, dưới hình thức Windows (.xaml), tôi chỉ cần đặt tham chiếu đến thư viện đó, một cái gì đó giống như

<Window x:Class="MyAppNamespace.MyView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ... /> 

    <Window.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
     <!-- Common base theme --> 
     <ResourceDictionary Source="pack://application:,,,/MyLibrary;component/Themes/MyMainThemeWrapper.xaml" /> 
     </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </Window.Resources> 

    <Rest of XAML for the WPF window> 

</Window> 

Các "thành phần" xuất hiện để ám chỉ vào thư mục gốc của dự án "MyLibrary" nhất định. Trong dự án thực tế, tôi đã tạo một thư mục con được gọi là "Chủ đề", do đó nguồn này bao gồm ...; thành phần/Chủ đề/...

"MyMainThemeWrapper.xaml" rất giống với từ điển được kết hợp của bạn, và nó thấy mọi thứ hoàn hảo từ các thư viện khác.

+0

Điều đó sẽ không tác động vào UserControl của tôi tại thời điểm designtime. Và, ngay cả khi tôi tham chiếu thư viện tài nguyên từ điển trong UserControl của tôi, thì điều đó vẫn sẽ được nhúng vào UserControl. Tôi có thể cần phải làm cho câu hỏi một chút rõ ràng hơn, nhưng tôi cần một cái gì đó có thể được làm việc với thiết kế (mặc định), mà sau đó có thể được ghi đè tại thời gian chạy (một nội dung resourcedictionary.xaml, không nhúng) –

0

Đây là giải pháp một phần của riêng bạn cho sự cố của bạn. Tôi đã không cố gắng để xử lý tài nguyên lỏng lẻo, nhưng tôi có một số thành công với việc chia sẻ tài nguyên giữa WinForms và WPF.

  • Tạo thư viện lớp để chứa tài nguyên của bạn trong tệp .ResX (ví dụ: Resources.resx, Resources.fr.resx, vv)
  • Tạo điều khiển WPF của bạn trong một thư viện điều khiển người dùng WPF
  • Tạo WinForms bạn đăng cai
  • tham khảo các nguồn lực trong thư viện tài nguyên của bạn từ WPF sử dụng phần mở rộng Infralution.Localization.Wpf đánh dấu và quản lý văn hóa, ví dụ

    <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/> 
    
  • Đặt nội dung của người dùng điều khiển WPF của bạn vào một hoặc nhiều từ điển tài nguyên như các mẫu kiểm soát, e, g

    <ControlTemplate x:Key="TestTemplate"> 
        <Grid> 
         <Grid.RowDefinitions> 
          <RowDefinition/> 
          <RowDefinition/> 
         </Grid.RowDefinitions> 
    
         <TextBlock Text="{Resx ResxName=ResourceLib.Resources, Key=Test}"/> 
        </Grid> 
    </ControlTemplate> 
    
  • Sử dụng mẫu tài nguyên trong người dùng của bạn điều khiển

    <UserControl x:Class="WpfControls.UserControl1" 
          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" mc:Ignorable="d" 
          d:DesignHeight="300" d:DesignWidth="300" > 
        <UserControl.Resources> 
         <ResourceDictionary> 
          <ResourceDictionary.MergedDictionaries> 
           <ResourceDictionary Source="ResourceDictionary.xaml"/> 
          </ResourceDictionary.MergedDictionaries> 
         </ResourceDictionary> 
        </UserControl.Resources> 
        <ContentControl Template="{StaticResource TestTemplate}" /> 
    </UserControl> 
    
  • Thêm một vài dòng mã để làm mọi thứ hoạt động

    public partial class UserControl1 : UserControl 
    { 
        // we require a reference to the resource library to ensure it's loaded into memory 
        private Class1 _class1 = new Class1(); 
    
        public UserControl1() 
        { 
         // Use the CultureManager to switch to the current culture 
         CultureManager.UICulture = Thread.CurrentThread.CurrentCulture; 
    
         InitializeComponent(); 
        } 
    } 
    

Dưới đây là một đơn giản demo app gọi WindowsFormsHost.7z

+0

Điều này khác với những gì @DRapp đề nghị? –

+0

Tôi cũng khắc phục sự cố 'Content = "{StaticResource SomeVariableName}"' bằng cách đặt một ContentControl trong UserControl của bạn, không gây rối với app.xaml. UserControl có thể được bản địa hóa và chia sẻ tài nguyên với WinForms bằng cách sử dụng các tệp .ResX. Làm thế nào là nó giống nhau? – Phil

Các vấn đề liên quan