2010-03-04 45 views
10

Tôi viết một ứng dụng WPF trên WinXP và tôi đã ghi đè các theme mặc định với chủ đề vista như thế này:Override ghi đè WPF Theme

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 

    var themerd = new ResourceDictionary(); 
    themerd.Source = new Uri(@"PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\themes/aero.normalcolor.xaml", UriKind.Relative); 

    Resources.MergedDictionaries.Add(themerd); 
} 

Và nó hoạt động tốt chủ yếu. Khi tôi sử dụng kiểm soát như một nút:

<Button /> 

Phong cách có vẻ tốt đẹp, nhưng nếu tôi sử dụng một nút với một phong cách khác nhau như thế này:

<Button> 
    <Button.Style> 
    <Style TargetType="Button"> 
     <Setter Property="Width" Value="80" /> 
    </Style> 
    </Button.Style> 
</Button> 

Phong cách sẽ ghi đè lên phong cách chủ đề cụ thể với phong cách WinXP tiêu chuẩn thay vì xây dựng trên đầu trang của nó. Điều này cực kỳ hạn chế đối với tôi. Có cách nào để tránh vấn đề này không?

Trả lời

10

Tại sao điều này xảy ra

Giá trị mặc định Basedon = cho một phong cách được tạo ra sử dụng chỉ từ điển tài nguyên các chủ đề hiện tại của. Kỹ thuật bạn hiển thị để ghi đè chủ đề không thực sự thay đổi từ điển chủ đề đang sử dụng: Nó chỉ thêm các tài nguyên từ từ điển tài nguyên của chủ đề vào từ điển tài nguyên của ứng dụng. Vì chủ đề hiện tại không thay đổi, nên BaseOn mặc định cũng không thay đổi.

Làm thế nào để giải quyết nó

Lựa chọn 1: Tại địa phương ghi đè lên các chủ đề bằng cách chặn cuộc gọi đến uxtheme.dll GetCurrentThemeName ở cấp Win32!. Điều này khá phức tạp nhưng hoạt động cho tất cả các kiểu của bạn mà không có thay đổi đối với XAML của bạn.

Tùy chọn 2: Đặt BasedOn bằng cách sử dụng MarkupExtension tùy chỉnh. Nó sẽ trông như thế này:

<Style TargetType="Button" BasedOn="{DefaultAeroStyle Button}"> ... 

MarkupExtension tùy chỉnh của bạn sẽ tải từ điển chủ đề Aero lên lần đầu tiên và lưu trữ trong trường tĩnh. Constructor của nó sẽ lấy một Type, và nó sẽ cung cấp kiểu tìm kiếm trong từ điển để tìm kiểu.

Tùy chọn 3: Đặt BasedOn thành kiểu được đặt tên trung gian. Nó sẽ giống như thế này:

<Application ...> 
    <Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
     <ResourceDictionary Source="... theme path ..." /> 
     </ResourceDictionary.MergedDictionaries> 

     <Style x:Key="ThemeButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" /> 
     <Style x:Key="ThemeListBoxStyle" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}" /> 
     ... 
    </ResourceDictionary> 
    </Application.Resources> 
</Application> 

Bây giờ trong từ điển cấp dưới của bạn, bạn có thể nói:

<Style TargetType="Button" BasedOn="{StaticResource ThemeButtonStyle}" /> 

Lựa chọn 4: Set Basedon sử dụng một thuộc tính tĩnh và x: mở rộng đánh dấu tĩnh

+1

Cảm ơn, câu trả lời của bạn thực sự hữu ích. Khu vực này có vẻ thiếu WPF. Bạn thường sử dụng tùy chọn nào để giải quyết vấn đề này? –

+0

Tùy chọn 2 rất thú vị, ở một mức độ nào đó, nó thậm chí còn xoay quanh vấn đề không được dựa trên BasedOn DynamicResources. –

+0

Tôi thường giải quyết vấn đề bằng cách giải thích cho khách hàng rằng tốt nhất là nên gắn bó với chủ đề OS hiện tại vì các cửa sổ sẽ trông "bình thường" đối với người dùng cuối. Tuy nhiên tôi đã sử dụng cả hai lựa chọn 2 và lựa chọn 3 trong các tình huống mà tôi cần một phần của giao diện người dùng được thiết kế lại nhưng một phần bên trong của giao diện người dùng (chẳng hạn như một cửa sổ bật lên) để * không * được thiết kế lại. –