2

メニュー システムとして機能する単純なカスタム コントロールを開発しています。2 つのボタンで構成されています: 戻るとホーム、および上記のメニュー項目です。ControlTemplate は次のようになります。

  <ControlTemplate x:Key="FancyColorPickerTemplate">
        <menu:BusyDecorator x:Name="BusyDecorator"  Style="{StaticResource BusyDecoratorStyle}">
            <menu:BusyDecorator.IsBusyIndicatorShowing>
                <PriorityBinding>
                    <Binding Path="IsBusy" RelativeSource="{RelativeSource AncestorType={x:Type CustomControls:Menu}}"/>
                </PriorityBinding>
            </menu:BusyDecorator.IsBusyIndicatorShowing>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.70*"/>
                    <RowDefinition Height="0.30*"/>
                </Grid.RowDefinitions>

                <ItemsControl Grid.Row="0" Name="Part_ItemControl" 
                        ItemTemplateSelector="{StaticResource imgStringTemplateSelector}"
                          HorizontalAlignment="Center" VerticalAlignment="Center">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapPanel Orientation="Horizontal"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
                <Button  Grid.Row="1" Name="PART_BackButton"  FontSize="20" Content="Back" HorizontalAlignment="Left" />
                <Button  Grid.Row="1" Name="PART_HomeButton"  FontSize="20" Content="Home" HorizontalAlignment="Center" />
            </Grid>
        </menu:BusyDecorator>
    </ControlTemplate>

ItemsControl には、表示された要素 (ボタンまたは UserControl) の DataTemplate を選択するための ItemTemplateSelector があります。例 :

    <DataTemplate x:Key="ButtonTemplate">
        <Grid Margin="10,0,10,0">
            <Button Content="{Binding Title}" ></Button>
          </Grid>
    </DataTemplate>

    <DataTemplate x:Key="UserControlTemplate">
        <Grid Margin="10,0,10,0">
            <CustomControls:ColorPickerUserControl Width="200"   Height="200"/>
        </Grid>
    </DataTemplate>

Codebehind では、クリックされた要素を確認し、必要に応じて (ItemsControl の ItemsSource プロパティを設定して) サブメニューを読み込みます。

 void Menu_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        ItemsControl itemsControl = GetTemplateChild("Part_ItemControl") as ItemsControl;
        object item = GetElementFromPoint(itemsControl, e.GetPosition(itemsControl));

        if (item != null && item is MenuItem2)
        {
            MenuItem2 mi = item as MenuItem2;
            if (mi.SubMenu != null)
            {
                IsBusy = true;
                Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                 {
                     MenuItems = new ObservableCollection<MenuItem2>(mi.SubMenu.Items);
                     IsBusy = false;
                 }));
                m_MenuStack.Push(mi.SubMenu);
            }
            else
            {
                if (!IsBusy)
                {
                    ExecuteAction(mi.Ac);
                }
            }
        }
        else
            Console.WriteLine("no item found");
    }

上記のコードの MenuItems は ItemsSource プロパティにバインドされ、ItemsControl を再評価し、DataTemplateSelector に基づいて対応する DataTemplate を適用します。私のコードの問題は、BusyDecorator (xaml を参照) を表示する必要がある上記の IsBusy プロパティにあり、DataTemplate は表示に時間がかかる UserControl です。UserControl が UI スレッドに読み込まれていると思われ、IsBusy プロパティが UI スレッドでアクションをトリガーするため、機能しません。

私は間違ったアプローチに従っていますか? これを機能させる方法はありますか?

4

1 に答える 1

0

ビジー セットのレンダリングが完了した後、常にビジー フラグを設定し、残りの作業を UI スレッドでスケジュールすることができます。

ここでの魔法の部分は、System.Windows.Threading.DispatcherPriority.Renderレンダリングと同時にタスクを実行する優先度を使用してスレッドがスケジュールされることです。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Click="Button_Click_1">LongTask</Button>
        <TextBlock Grid.Row="1" Text="{Binding IsBusy}"/>
    </Grid>
</Window>

と背後にあるコード

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public bool IsBusy
        {
            get { return (bool)GetValue(IsBusyProperty); }
            set { SetValue(IsBusyProperty, value); }
        }

        public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            IsBusy = true;
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                Thread.Sleep(2000);

                IsBusy = false;
            }), System.Windows.Threading.DispatcherPriority.Render, null);
        }
    }
}
于 2013-04-16T12:43:13.433 に答える