WPF从列表框mvvm更新项目

时间:2017-01-27 20:00:50

标签: c# wpf xaml mvvm listbox

我有一个列表框,我将绑定项目。我允许用户添加/删除文本文件并将其附加到对象。发生这种情况时,我希望项目更新。

我从未见过这种更新。我试图使用ConotentControl并通过样式和ContentTemplateSelector操作它没有成功。我显然有一个不正确的绑定,但我无法确定它的位置。

我可以看到该值确实是通过Live Property Explorer更新的。

public enum FileState{None,Valid,Invalid};
public class AppPathLoc:ViewModelBase
{

    #region FileState
    /// <summary>
    /// The <see cref="FileState" /> property's name.
    /// </summary>
    private const string FileStatePropertyName = "FileState";

    private FileState _fileState = FileState.None;

    /// <summary>
    /// Sets and gets the FileState property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public FileState FileState
    {
        get
        {
            return _fileState;
        }

        set
        {
            if (_fileState == value)
            {
                return;
            }

            _fileState = value;
            OnPropertyChanged(FileStatePropertyName);
        }
    }
    #endregion


    private string _filename = string.Empty;

    [Localizable(false)]
    public string FileName
    {
        get
        {
            return _filename;
        }
        set
        {
            if (_filename != value)
            {
                _filename = value;
                OnPropertyChanged("FileName");
            }
        }
    }

}



 public class ApplicationsViewModel : ViewModelBase
{
    private IDataService _dataService;


    #region · Properties ·


    #region SelectedAppPathLocation
    /// <summary>
    /// The <see cref="SelectedAppPathLocation" /> property's name.
    /// </summary>
    private const string SelectedAppPathLocationPropertyName = "SelectedAppPathLocation";

    private AppPathLoc _selectedAppPathLocation = null;

    /// <summary>
    /// Sets and gets the SelectedAppPathLocation property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public AppPathLoc SelectedAppPathLocation
    {
        get
        {
            return _selectedAppPathLocation;
        }

        set
        {
            if (_selectedAppPathLocation == value)
            {
                return;
            }

            _selectedAppPathLocation = value;
            OnPropertyChanged(SelectedAppPathLocationPropertyName);
        }
    }
    #endregion


    #region SelectedController
    /// <summary>
    /// The <see cref="SelectedController" /> property's name.
    /// </summary>
    private const string SelectedControllerPropertyName = "SelectedController";

    private Controller _selectedController = null;

    /// <summary>
    /// Sets and gets the SelectedController property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public Controller SelectedController
    {
        get
        {
            return _selectedController;
        }

        set
        {
            if (_selectedController == value)
            {
                return;
            }

            _selectedController = value;
            OnPropertyChanged(SelectedControllerPropertyName);
        }
    }
    #endregion

    public ObservableCollection<string> LocationNames { get; set; }= new ObservableCollection<string>();
    public ObservableCollection<Controller> Controllers { get; set; }= new ObservableCollection<Controller>();
    public ObservableCollection<CApplication> Applications { get; set; } = new ObservableCollection<CApplication>();
    public ObservableCollection<AppPath> AppPaths { get; set; } = new ObservableCollection<AppPath>();

    public ObservableCollection<AppPathLoc> AppPathLocs { get; set; } = new ObservableCollection<AppPathLoc>();
    #endregion


    #region · Commands ·


    #region · RemoveTextCommand ·
    private RelayCommand<AppPathLoc> _removeTextCommand;

    /// <summary>
    /// Gets the RemoveTextCommand.
    /// </summary>
    public RelayCommand<AppPathLoc> RemoveTextCommand
    {
        get
        {
            return _removeTextCommand
                ?? (_removeTextCommand = new RelayCommand<AppPathLoc>(ExecuteRemoveTextCommand));
        }
    }

    private async void ExecuteRemoveTextCommand(AppPathLoc appPathLoc)
    {
        var msgText = $"Removed TextBlock file {appPathLoc.FileName} for {appPathLoc.Location.LocName}";
        var name = appPathLoc.FileName;
        appPathLoc.BFile = null;
        appPathLoc.FileName = null;
        appPathLoc.OnPropertyChanged("FileState");
        OnPropertyChanged("AppPathLocs");
        var result = await _dataService.SaveAppPathLocationAsync(appPathLoc);
        if (result != null)
        {



            var msg = new SnackbarMessage { Content = msgText  };


            Kuka.UI.WPF.ViewModel.Messaging.Messenger.Default.Send(msg);

            SelectedAppPathLocation.LoadFileName();
        }
    }
    #endregion

    #region · AddTextCommand ·
    private RelayCommand<AppPathLoc> _addTextCommand;

    /// <summary>
    /// Gets the AddTextCommand.
    /// </summary>
    public RelayCommand<AppPathLoc> AddTextCommand
    {
        get
        {
            return _addTextCommand
                ?? (_addTextCommand = new RelayCommand<AppPathLoc>(ExecuteAddTextCommand));
        }
    }

    private async void ExecuteAddTextCommand(AppPathLoc appPathLoc)
    {
        if (appPathLoc == null)
            return;
        var dlg = new OpenFileDialog
        {
            Filter = Constants.TEXT_FILE_FILTER,
            InitialDirectory = Constants.BLOCK_PATH + SelectedController.RobotVendor.RvName
        };

        if(appPathLoc.FileState==FileState.Valid)
            dlg.InitialDirectory = Path.GetDirectoryName(appPathLoc.BFile);

        if (dlg.ShowDialog().GetValueOrDefault())
        {
            appPathLoc.DialogName = "";
            appPathLoc.BFile = dlg.FileName;
            appPathLoc.FileName = Path.GetFileName(dlg.FileName);
            appPathLoc.LoadFileName();

            await DispatcherHelper.RunAsync(() =>
            {


                appPathLoc.OnPropertyChanged("FileState");
                OnPropertyChanged("SelectedAppPathLocation");
                OnPropertyChanged("AppPathLocs");
            });
            appPathLoc.LoadFileName();
            var result = await _dataService.SaveAppPathLocationAsync(appPathLoc);
            var msgText = $"Added TextBlock file {result.FileName} for {result.Location.LocName}";
            var msg = new SnackbarMessage { Content = msgText };



            Kuka.UI.WPF.ViewModel.Messaging.Messenger.Default.Send(msg);



            //                SelectedAppPathLoc.OnPropertyChanged("FileName");
        }
    }
    #endregion

    #region · AddAppPathLocationCommand ·
    private RelayCommand<AppPath> _addAppPathLocationCommand;

    /// <summary>
    /// Gets the AddAppPathLocationCommand.
    /// </summary>
    public RelayCommand<AppPath> AddAppPathLocationCommand
    {
        get
        {
            return _addAppPathLocationCommand
                ?? (_addAppPathLocationCommand = new RelayCommand<AppPath>(ExecuteAddAppPathLocationCommand));
        }
    }

    private  void ExecuteAddAppPathLocationCommand(AppPath appPath)
    {

    }
    #endregion


    #region · RemoveAppPathLocationCommand ·
    private RelayCommand<AppPathLoc> _removeAppPathLocationCommand;

    /// <summary>
    /// Gets the RemoveAppPathLocationCommand.
    /// </summary>
    public RelayCommand<AppPathLoc> RemoveAppPathLocationCommand
    {
        get
        {
            return _removeAppPathLocationCommand
                ?? (_removeAppPathLocationCommand = new RelayCommand<AppPathLoc>(ExecuteRemoveAppPathLocationCommand));
        }
    }

    private  void ExecuteRemoveAppPathLocationCommand(AppPathLoc appPathLoc)
    {

    }
    #endregion

    #region · GetTextBlockCommand ·
    private RelayCommand<AppPathLoc> _getTextBlockCommand;

    /// <summary>
    /// Gets the GetTextBlockCommand.
    /// </summary>
    public RelayCommand<AppPathLoc> GetTextBlockCommand
    {
        get
        {
            return _getTextBlockCommand
                ?? (_getTextBlockCommand = new RelayCommand<AppPathLoc>(ExecuteGetTextBlockCommand));
        }
    }

    private void ExecuteGetTextBlockCommand(AppPathLoc appPathLoc)
    {

    }
    #endregion
    #region · ControllerChangedCommand ·

    private RelayCommand<Controller> _controllerChangedCommand;

    /// <summary>
    /// Gets the ControllerChangedCommand.
    /// </summary>
    public RelayCommand<Controller> ControllerChangedCommand
    {
        get
        {
            return _controllerChangedCommand
                ?? (_controllerChangedCommand = new RelayCommand<Controller>(ExecuteControllerChangedCommand));
        }
    }

    private async void ExecuteControllerChangedCommand(Controller controller)
    {
        Applications.Clear();
        AppPaths.Clear();
        AppPathLocs.Clear();
        var applications =await _dataService.GetApplicationsAsync(controller.ContNum);
        if (applications != null)
        {
            Applications = new ObservableCollection<CApplication>(applications);
            OnPropertyChanged("Applications");

        }

    }
    #endregion


    #region · ApplicationChangedCommand ·
    private RelayCommand<CApplication> _applicationChangedCommand;

    /// <summary>
    /// Gets the ApplicationChangedCommand.
    /// </summary>
    public RelayCommand<CApplication> ApplicationChangedCommand => _applicationChangedCommand
                                                                   ?? (_applicationChangedCommand = new RelayCommand<CApplication>(ExecuteApplicationChangedCommand));

    private async void ExecuteApplicationChangedCommand(CApplication application)
    {
        AppPaths.Clear();

        if (application == null)
            return;
        if (!IsInDesignModeStatic)

            AppPathLocs.Clear();
        var appPaths = await _dataService.GetAppPathsAsync(application.CAppNum);
        if (appPaths != null)
        {
            AppPaths = new ObservableCollection<AppPath>(appPaths);
            OnPropertyChanged("AppPaths");
        }

        var appPathLocs = await _dataService.GetAppPathLocationsAsync(application);
        if (appPathLocs != null)
        {

            AppPathLocs = new ObservableCollection<AppPathLoc>(appPathLocs);
            OnPropertyChanged("AppPathLocs");

            OnPropertyChanged("AppPathLocs");
        }

    }
    #endregion



    #region · AppPathsChangedCommand ·
    private RelayCommand<AppPath> _appPathsChangedCommand;

    /// <summary>
    /// Gets the AppPathsChangedCommand.
    /// </summary>
    public RelayCommand<AppPath> AppPathsChangedCommand => _appPathsChangedCommand
                                                           ?? (_appPathsChangedCommand = new RelayCommand<AppPath>(ExecuteAppPathsChangedCommand));

    private async void ExecuteAppPathsChangedCommand(AppPath appPath)
    {
        if(!IsInDesignModeStatic)
        AppPathLocs.Clear();
        if (appPath == null)
            return;
        var appPathLocs = await _dataService.GetAppPathLocationsAsync(appPath.AppPathID);
        if (appPathLocs != null)
        {
            AppPathLocs = new ObservableCollection<AppPathLoc>(appPathLocs);
            OnPropertyChanged("AppPathLocs");
        }


    }
    #endregion


    #endregion
    /// <summary>
    /// Initializes a new instance of the ApplicationsViewModel class.
    /// </summary>
    public ApplicationsViewModel(IDataService dataService)
    {
        _dataService = dataService;
        if(!(IsInDesignMode||IsInDesignModeStatic))
            GetData();
    }

    private async void GetData()
    {
        var locationNames = await _dataService.GetLocationNamesAsync().ContinueWith(r =>
        {
            return r.Result.GroupBy(o => o).Select(o => o.Key).ToList();
        });
        if (locationNames != null)
        {
            LocationNames=new ObservableCollection<string>(locationNames);
            OnPropertyChanged("LocationNames");
        }
        var controllers = await _dataService.GetControllersAsync();
        if (controllers != null)
        {
            Controllers = new ObservableCollection<Controller>(controllers);
            OnPropertyChanged("Controllers");
        }

        if (IsInDesignMode || IsInDesignModeStatic)
        {

            /*
            const int max = 15;
            var rnd = new Random();

            var files = Directory.EnumerateFiles("D:\\Temp", "*.txt", SearchOption.AllDirectories)
                .Take(max);

            for (var i = 0; i < 30; i++)
            {

                var num = rnd.Next(0,max);
                var apl = new AppPathLoc();
                apl.Location = new Location {LocName = $"Item {num}"};
                var file = files.ElementAt(num);
                apl.BFile = file;
                apl.FileName = Path.GetFileName(file);
                AppPathLocs.Add(apl);
            }

            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(5);
            timer.Tick += (s, e) =>
            {
                var idx = rnd.Next(0, max);
                var apl = AppPathLocs[idx];
                apl.BFile = apl.BFile == null ? files.ElementAt(idx) : null;
                apl.LoadFileName();

            };
            timer.IsEnabled = true;
            */
        }



    }


}

XAML

<Grid  Style="{StaticResource Grid}" >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <wpf:ColorZone Padding="4 0" wpf:ShadowAssist.ShadowDepth="Depth2" Mode="Light" VerticalAlignment="Stretch" Margin="0 0 4 0"  >
        <Grid Margin="8">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.Resources>

                <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboSelectorText}"/>
            </Grid.Resources>

            <!-- Controller -->
            <ComboBox ItemsSource="{Binding Controllers}" 
                      x:Name="Controllers"
                      Grid.Column="0"
                      SelectedIndex="0"
                     SelectedItem="{Binding SelectedController }"
                      wpf:HintAssist.Hint="Controllers"
                      wpf:HintAssist.IsFloating="True"

                      DisplayMemberPath="ContName"
                      IsSynchronizedWithCurrentItem="True" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <command:EventToCommand Command="{Binding ControllerChangedCommand, Mode=OneWay}"  CommandParameter="{Binding SelectedItem,ElementName=Controllers}"/>
                    </i:EventTrigger>

                </i:Interaction.Triggers>
            </ComboBox>


            <!-- Applications-->
            <ComboBox
                x:Name="Applications"
                SelectedIndex="0"
                Grid.Column="1"
                wpf:HintAssist.Hint="Applications"
                wpf:HintAssist.IsFloating="True"

                ItemsSource="{Binding Applications}"
                DisplayMemberPath="AppType.AppTypeName"
                >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <command:EventToCommand Command="{Binding ApplicationChangedCommand, Mode=OneWay}"  CommandParameter="{Binding SelectedItem,ElementName=Applications}"/>
                    </i:EventTrigger>

                </i:Interaction.Triggers>
            </ComboBox>

            <!-- AppPaths-->
            <ComboBox
                x:Name="AppPaths"
                SelectedIndex="0"
                Grid.Column="2"
                wpf:HintAssist.Hint="AppPaths"
                wpf:HintAssist.IsFloating="True"

                ItemsSource="{Binding AppPaths}"
                DisplayMemberPath="StandardPath.PathName"
                >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <command:EventToCommand Command="{Binding AppPathsChangedCommand, Mode=OneWay}"  CommandParameter="{Binding SelectedItem,ElementName=AppPaths}"/>
                    </i:EventTrigger>

                </i:Interaction.Triggers>
            </ComboBox>


        </Grid>

    </wpf:ColorZone>
    <wpf:ColorZone Grid.Row="1" VerticalAlignment="Stretch" Margin="8" >
        <GroupBox Header="Locations">
            <ListBox ItemsSource="{Binding AppPathLocs,IsAsync=True}" x:Name="AppPathLocations" SelectedItem="{Binding SelectedAppPathLocation}"  IsSynchronizedWithCurrentItem="True"  >
                <ListBox.Resources>
                    <DataTemplate DataType="{x:Type dataLinqClasses:AppPathLoc}" >
                        <view:AppPathLocListItemView/>
                    </DataTemplate>

                </ListBox.Resources>
                <ListBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource MaterialDesignCardsListBoxItem}">
                        <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                        <Setter Property="Padding" Value="4 0"/>




                    </Style>
                </ListBox.ItemContainerStyle>
                <ListBox.ContextMenu>
                    <ContextMenu  DataContext="{Binding Path=ApplicationsModel, Source={StaticResource Locator}}">
                        <MenuItem Header="Locations">

                            <MenuItem Header="Add Location"  Command="{Binding AddAppPathLocationCommand,Mode=OneWay}" Style="{StaticResource AddStyle}"/>
                            <MenuItem Header="Remove Location" Command="{Binding RemoveAppPathLocationCommand,Mode=OneWay}" CommandParameter="{Binding SelectedAppPathLocation}" Style="{StaticResource RemoveStyle}"/>
                        </MenuItem>


                        <MenuItem  Header="{x:Static simulationWorkflow:Constants.ADD_TEXT_BLOCK_HEADER}"   Command="{Binding AddTextCommand,Mode=OneWay}" CommandParameter="{Binding SelectedAppPathLocation}" Style="{DynamicResource AddStyle}" />
                        <MenuItem Header="{x:Static simulationWorkflow:Constants.REMOVE_TEXT_BLOCK_HEADER}" Command="{Binding RemoveTextCommand,Mode=OneWay}" Style="{DynamicResource RemoveStyle}"  CommandParameter="{Binding SelectedAppPathLocation}"/>
                        <MenuItem  Header="{x:Static simulationWorkflow:Constants.OPEN_FILE_LOCATION}" Command="{x:Static commands:StaticCommands.OpenAppPathCommand}" CommandParameter="{Binding SelectedAppPathLocation.BFile}"/>

                    </ContextMenu>

                </ListBox.ContextMenu>
            </ListBox>
        </GroupBox>


    </wpf:ColorZone>

    <Button Style="{DynamicResource MaterialDesignFloatingActionButton}" VerticalAlignment="Bottom" Grid.Row="1" HorizontalAlignment="Right" Panel.ZIndex="999" Margin="16">
        <wpf:PackIcon Kind="Plus"/>
    </Button>
</Grid>

物品

<Grid   Margin="8" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="AppPathGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>

        <RowDefinition Height="*" MinHeight="30"/>
    </Grid.RowDefinitions>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="Name : " Grid.Column="0" Style="{DynamicResource MaterialDesignTitleTextBlock}" VerticalAlignment="Center" Padding="0 0 4 0"/>
        <TextBox Text="{Binding Location.LocName}" Grid.Row="0" Grid.Column="1" Style="{StaticResource  TitleTextBox}"/>
    </Grid>
    <Expander Grid.Row="1">
         <Expander.HeaderTemplate>
            <DataTemplate DataType="{x:Type dataLinqClasses:AppPathLoc}">
                <Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0">

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="File : " Grid.Column="0"/>
                    <TextBlock Grid.Column="1" Text="{Binding Path=FileName}"/>
                    </Grid>
                    <Grid Grid.Row="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="File "/>
                            <TextBlock Text="{Binding FileName}"/>
                            <TextBlock Text=" is specified but doesn't exist!"/>
                        </StackPanel>
                        <wpf:PackIcon Kind="AlertCircle" Grid.Column="1">
                            <wpf:PackIcon.Triggers>
                                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation From="1" To="0" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever" Storyboard.TargetProperty="Opacity"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </wpf:PackIcon.Triggers>
                        </wpf:PackIcon>
                    </Grid>
                </Grid>
            </DataTemplate>
        </Expander.HeaderTemplate>

        <Expander.Style>
            <Style TargetType="{x:Type Expander}" BasedOn="{StaticResource {x:Type Expander}}">
                <Setter Property="Background" Value="Orange"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=FileState}" Value="{x:Static dataLinqClasses:FileState.Valid}">
                        <Setter Property="Background" Value="Red"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding FileState, IsAsync=True}" Value="Valid">
                        <Setter Property="Background" Value="Blue"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=FileState}" Value="{x:Static dataLinqClasses:FileState.Invalid}">
                        <Setter Property="Background" Value="Yellow"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding FileState, IsAsync=True}" Value="Invalid">
                        <Setter Property="Background" Value="Green"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=FileState}" Value="{x:Static dataLinqClasses:FileState.None}">
                        <Setter Property="Background" Value="Orange"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding FileState, IsAsync=True}" Value="None">
                        <Setter Property="Background" Value="Cyan"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Expander.Style>

        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewMouseDown">
                <command:EventToCommand Command="{Binding ApplicationsModel.GetTextBlockCommand, Mode=OneWay, Source={StaticResource Locator}}"  CommandParameter="{Binding}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <Border BorderBrush="Black" BorderThickness="1">

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBox Style="{x:Null}" Text="{Binding TextBlock}" AcceptsReturn="True" TextWrapping="Wrap"/>
                <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal" Margin="2">
                    <Button Content="Change File"/>
                    <Button Content="Save"/>
                    <Button Content="Close"/>
                </StackPanel>
            </Grid>
        </Border>
    </Expander>



</Grid>

现在我试图开始工作的基本上是在文件状态值发生变化时改变背景颜色。

1 个答案:

答案 0 :(得分:0)

实际问题解决了,因为我使用Linq2Sql,但在我的部分类中我也实现了两次INotifyPropertyChanged