Изменить содержимое кнопки MVVM - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть кнопка со следующим содержанием:

 <StackPanel Orientation="Horizontal">

                <TextBlock Text="Connect"/>
                <materialDesign:PackIcon Kind="Arrow"/>
  </StackPanel>

Я искал и нашел это: Привязка содержимого кнопки WPF , но я не уверен, как применить решение, когда у меня есть все три: Stackpanel, PackIcon (объект) и Textblock.

У меня есть этот индикатор прогресса, который я делаю, он появляется под кнопкой:

 <ProgressBar  x:Name="XZ" Foreground="Black" Grid.Row="4" Grid.Column="1"
                  Visibility="{Binding Connecting, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
            Value="50"
            IsIndeterminate="True" />

Я хочу сделать так, чтобы при нажатии кнопки вместо того, чтобы показывать панель ProgressBar там, где она сейчас находится, нужно в основном удалить Text и PackIcon и поместить ProgressBar в кнопку.

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

Вы можете создать шаблон для кнопки, чтобы добиться этого, а затем повторно использовать шаблон везде, где вы хотите кнопку с загрузкой, следующим образом:

    <Button Width="120" Height="40" Tag="False" Name="loadingButton" Click="loadingButton_Click">
    <Button.Template>
        <ControlTemplate>
            <Border Name="PART_Border" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Background="Transparent">
                <Grid Name="PART_Root">
                    <TextBlock Name="PART_Text" HorizontalAlignment="Center" VerticalAlignment="Center">Data</TextBlock>
                    <ProgressBar  IsIndeterminate="True"  Name="PART_Loading"></ProgressBar>
                </Grid>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="Tag" Value="True">
                    <Setter TargetName="PART_Text" Property="Visibility" Value="Collapsed"></Setter>
                    <Setter TargetName="PART_Loading" Property="Visibility" Value="Visible"></Setter>
                </Trigger>

                <Trigger Property="Tag" Value="False" >
                    <Setter TargetName="PART_Text" Property="Visibility" Value="Visible"></Setter>
                    <Setter TargetName="PART_Loading" Property="Visibility" Value="Collapsed"></Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

И событие для нажатия кнопки будет:

    private async void loadingButton_Click(object sender, RoutedEventArgs e)
    {
        loadingButton.Tag = true.ToString();//display loading
        await Task.Run(() => { Thread.Sleep(4000); });//fake data loading
        loadingButton.Tag = false.ToString();//hide loading
    }

Обратите внимание, что вы также можете связать свойство Tag для свойства внутри вашей модели представления, если вы используете шаблон MVVM.

0 голосов
/ 27 апреля 2018

Вы можете использовать шаблон данных. Что-то вроде: XAML:

    <Window.Resources>
    <DataTemplate DataType="{x:Type local:ButtonInfo}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label Grid.Row="0" Content="Press me"></Label>
            <Label Grid.Row="1" Content="{Binding Label}"></Label>
        </Grid>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:ProgressInfo}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <ProgressBar Height="30" Value="{Binding Progress}"></ProgressBar>
            <Label Grid.Row="1" Content="{Binding Label}"></Label>
        </Grid>
    </DataTemplate>
</Window.Resources>


   <Grid>
        <Button Command="{Binding ProcessCommand}" Content="{Binding ButtonInfo}">            
        </Button>
    </Grid>

C #:

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel();
    }
}

public class ViewModelBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class MainWindowViewModel:ViewModelBase
{
    public MainWindowViewModel()
    {
        ButtonInfo = new ButtonInfo(){Label = "Button Info"};
        ProcessCommand = new DelegateCommand(Process);
    }
    private ButtonInfo _buttonInfo;
    public ButtonInfo ButtonInfo
    {
        get { return _buttonInfo; }
        set
        {
            _buttonInfo = value;
            OnPropertyChanged();
        }
    }

    public DelegateCommand ProcessCommand { get; set; }

    private async void Process()
    {
        ButtonInfo = new ProgressInfo(){Label = "Progress Info"};
        await ProcessAsync();
    }

    private Task ProcessAsync()
    {
        return Task.Run(() =>
        {
            for (int i = 0; i < 100; i++)
            {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    ButtonInfo.Progress = i;
                    if (i==99)
                    {
                        ButtonInfo = new ButtonInfo(){Label = "Button Again"};
                    }
                });
                Thread.Sleep(100);
            }
        });
    }
}

public class ButtonInfo:ViewModelBase
{
    private string _label;
    private int _progress;
    private bool _isProcessing;

    public string Label
    {
        get { return _label; }
        set
        {
            _label = value;
            OnPropertyChanged();
        }
    }

    public int Progress
    {
        get { return _progress; }
        set
        {
            _progress = value;
            OnPropertyChanged();
        }
    }

    public bool IsProcessing
    {
        get { return _isProcessing; }
        set
        {
            _isProcessing = value;
            OnPropertyChanged();
        }
    }
}

public class ProgressInfo : ButtonInfo { }
0 голосов
/ 27 апреля 2018

На самом деле изменение в элементах управления может быть сделано с помощью триггеров данных; хотя в этом случае это кажется немного чрезмерным.

Я бы просто переключил видимость двух элементов управления:

<Grid>
    <StackPanel Orientation="Horizontal" Visibility="{Binding Connecting, Converter={StaticResource BooleanToCollapsedConverter}}"">

                <TextBlock Text="Connect"/>
                <materialDesign:PackIcon Kind="Arrow"/>
    </StackPanel>
    <ProgressBar  x:Name="XZ" Foreground="Black" Grid.Row="4" Grid.Column="1"
                  Visibility="{Binding Connecting, Converter={StaticResource BooleanToVisibilityConverter}}"
            Value="50"
            IsIndeterminate="True" />
</Grid>

Это будет содержимое вашей кнопки. BooleanToCollapsedConverter является инверсией VisibiltyToBooleanConverter; Есть несколько способов сделать это, и это оставлено в качестве упражнения.

в сторону; UpdateSourceTrigger не имеет смысла для привязки OneWay (она не обновляет источник!), И вам даже не нужно это для видимости, поскольку это не ввод, который пользователь может изменить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...