3

タイプの依存関係プロパティを持つカスタム WPF コントロールがありますPen(コントロール内の分割線のスタイルを設定するために使用されます)。

このプロパティの既定値はシステム カラーであると想定されています。この既定値を使用する場合、ユーザーが (Windows 設定で) システム カラーを変更すると、コントロールを更新する必要があります。

これまでのところ、このデフォルト値をデフォルト コントロール スタイルの一部として指定しました。

<Style TargetType="{x:Type my:Control}">
    <Setter Property="DividerPen">
        <Pen Brush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
             Thickness="1"/>
    </Setter>
    ...
</Style>

コントロールが単一の UI スレッドでのみ使用されている限り、これは正常に機能します。ただし、別の UI スレッドで実行される複数の最上位ウィンドウでコントロールを使用すると、次の例外が発生します。

System.Windows.Markup.XamlParseException: Cannot access Freezable 'System.Windows.Media.Pen' across threads because it cannot be frozen.
---> System.InvalidOperationException: Cannot access Freezable 'System.Windows.Media.Pen' across threads because it cannot be frozen.

at System.Windows.StyleHelper.ProcessInstanceValuesHelper(ItemStructList`1& valueLookupList, DependencyObject target, Int32 childIndex, HybridDictionary instanceValues, Boolean apply)
at System.Windows.StyleHelper.ProcessInstanceValuesForChild(DependencyObject container, DependencyObject child, Int32 childIndex, HybridDictionary instanceValues, Boolean apply, FrugalStructList`1& childRecordFromChildIndex)
at System.Windows.StyleHelper.CreateInstanceData(UncommonField`1 dataField, DependencyObject container, FrameworkElement fe, FrameworkContentElement fce, Style newStyle, FrameworkTemplate newFrameworkTemplate)
...

どうやら、<Pen>インスタンス内で動的リソースを使用すると、スタイルが凍結されるのを防ぐことができます。

これまでのところ、2 つの解決策を考えることができます。

1) スタイルにセットx:Shared="False"します。すべてのコントロール インスタンスは、既定のスタイルの独自のコピーを取得するため、固定する必要はありません。ただし、このスタイルには他にもいくつかのセッター (重要なテンプレートを含む) があるため、それらをコントロールの複数のインスタンスで共有できるようにしたいと考えています。

2) タイプのPenプロパティを、ブラシ、太さ、ダッシュ スタイルなどの個別のプロパティに分割します。これにより{DynamicResource}、スタイルのセッターで直接使用され、スタイルを固定できます。(ただし、スタイルがいつフリーズ可能になるかについての正確な詳細はわかりません)ペン型のプロパティが複数あり、それぞれにユーザーがカスタマイズしたいプロパティがかなりあるため、この解決策は望ましくありません。また、コントロールのパブリック API に重大な変更を導入することなく、この例外を修正したいと考えています。

他のアイデアはありますか?DividerPen プロパティにこの種の既定値を指定する他の方法はありますか?


複数の UI スレッドの意味について混乱があるように思われるので、独自のスレッドで新しいウィンドウを開くコードを次に示します。

    public void OpenNewWindow()
    {
        Thread t = new Thread(new ThreadStart(Run));
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

    void Run()
    {
        var window = new Window();
        window.Content = new MyUserControl();
        window.Show();
        // just for test purposes; a real multithreaded WPF app needs logic to shutdown the dispatcher when the window is closed
        Dispatcher.Run();
    }
4

1 に答える 1

0

あなたが何をしているのかを正確に理解するには、さらに多くのコードが必要になると思います。

スレッドをどのように定義したか、またはどのような種類のコンスティチュレーションで立ち往生しているかはわかりませんが、ここに例を示します。問題の解決策がどこかで見つかることを願っています.

これはアプリのリソース ディクショナリです。

<SolidColorBrush x:Key="redBrushKey" Color="Red"/>

<Pen x:Key="penKey" Brush="{DynamicResource redBrushKey}"/>

<Style TargetType="Rectangle">
  <Setter Property="Height" Value="50"/>
  <Setter Property="Width" Value="50"/>
  <Setter Property="Fill">
    <Setter.Value>
      <DrawingBrush>
        <DrawingBrush.Drawing>
          <GeometryDrawing Brush="Yellow" Pen="{StaticResource penKey}">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0,0,10,10"/>
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
        </DrawingBrush.Drawing>
      </DrawingBrush>
    </Setter.Value>
  </Setter>
</Style>

実行するウィンドウの数に関係なく、各長方形に適用されるスタイルを定義しました

そして、これは私が新しいウィンドウを開始する方法です:

private void OnStartNewWindow(object sender, RoutedEventArgs args)
{
    // Create and show the Window
    Window tempWindow = new Window();
    Rectangle rect = new Rectangle();
    StackPanel stackPanel = new StackPanel();
    stackPanel.Children.Add(rect);
    tempWindow.Content = stackPanel;
    tempWindow.Show();
}

そして、これは私のメインウィンドウです:

  <StackPanel>
    <Button Click="OnStartNewWindow">start new window</Button>
  </StackPanel>

メインウィンドウのボタンをクリックするだけで、ペンに指定した色が赤であるため、新しいウィンドウが開き、赤い境界線を持つ長方形が表示されます。

それはすべてうまくいきます。ViewModel 内で新しいウィンドウを実行する場合は、this.Dispatcher.Invoke の代わりに Application.Current.Dispatcher.Invoke メソッドを使用します。

コードでスタック パネルをウィンドウに追加しましたが、xaml でも機能します。

于 2014-03-10T14:38:32.270 に答える