首页 > 解决方案 > 数据模板中的按钮无法识别命令

问题描述

数据模板中的按钮与项目列表视图中的命令不起作用。我尝试过其他带有堆栈面板的数据模板。搜索初始项目的按钮将识别它的命令和工作。

这是包含项目数据模板的页面:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:local="clr-namespace:WpfFstApp1.Pages"
  xmlns:ViewModels="clr-namespace:WpfFstApp1.ViewModels" x:Class="WpfFstApp1.Pages.CsvPage"
  mc:Ignorable="d" 
  d:DesignHeight="450" d:DesignWidth="800"
  Title="CsvPage">


<Page.DataContext>
    <ViewModels:CsvViewModel/>
</Page.DataContext>


<Page.Resources>
    <DataTemplate x:Key="CsvTemp">
        <ListView>
            <TextBlock Text="{Binding Dir}"/>
            <TextBlock Text="{Binding FiPath}"/>
            <Button Content="Click To Open" Command="{Binding OpenFiCommand, Mode=OneWay}" CommandParameter="{Binding SelResult.FiPath}"></Button>
            <ListView ItemsSource="{Binding Refs}"/>
        </ListView>
    </DataTemplate>
</Page.Resources>


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="55"/>
        <RowDefinition/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>

    <TextBlock Text="Project" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top" Height="16" Width="37"/>
    <TextBlock Text="Sales Line" HorizontalAlignment="Left" Margin="65,5,0,0" VerticalAlignment="Top" Height="16" Width="52"/>
    <TextBlock Text="Part Number" HorizontalAlignment="Left" Margin="155,5,0,0" VerticalAlignment="Top" Height="16" Width="68"/>
    <TextBox x:Name="TxtBoxProj" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" VerticalAlignment="Top" Width="50" 
             TextAlignment="Right" MaxLines="1" Text="{Binding SearchVal1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxSline" HorizontalAlignment="Left" Height="23" Margin="65,26,0,0" VerticalAlignment="Top" Width="85" MaxLines="1" MaxLength="25" 
             TextAlignment="Right" CharacterCasing="Upper" Text="{Binding SearchVal2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxPart" HorizontalAlignment="Left" Height="23" Margin="155,26,0,0" VerticalAlignment="Top" Width="120" 
             TextAlignment="Right" MaxLines="1" CharacterCasing="Upper" Text="{Binding SearchVal3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

    <Button x:Name="BtnSrch" Content="Search" HorizontalAlignment="Left" Margin="280,29,0,0" VerticalAlignment="Top" Width="40" Command="{Binding SearchCommand, Mode=OneWay}"/>

    <ListView Margin="10" Grid.Row="1" ItemsSource="{Binding OcResults}" ItemTemplate="{Binding Mode=OneWay, Source={StaticResource CsvTemp}}" SelectedItem="{Binding SelResult}"/>

    <StatusBar Grid.Row="2" FontSize="14" Margin="1,0,1,1" VerticalAlignment="Bottom">
        <TextBlock x:Name="tsTxtBlck1" Text="{Binding CurStat1}" />
        <TextBlock x:Name="tsTxtBlck2" Text="{Binding CurStat2}"/>
    </StatusBar>

</Grid>

这是模型:

class SearchResult
{
    public string Dir { get; set; }
    public string FiName { get; set; }
    public string FiPath { get; set; }
    public List<string> Refs { get; set; }
}

这是我的视图模型:

class CsvViewModel : ModelBase
{

    #region [ Declarations ]
    //
    bool Init = false;
    string CurDir = string.Empty;
    //Count of files traversed and timer for diagnostic output
    int fileCount = 0;
    Stopwatch sw;
    public List<SearchResult> ResList;
    //
    #endregion


    #region [ Properties ]
    //
    public ObservableCollection<SearchResult> OcResults { get; set; }
    //
    private string _curStat1;
    public string CurStat1
    {
        get { return _curStat1; }
        set { _curStat1 = value; OnPropertyChanged(nameof(CurStat1)); }
    }

    private string _curStat2;
    public string CurStat2
    {
        get { return _curStat2; }
        set { _curStat2 = value; OnPropertyChanged(nameof(CurStat2)); }
    }
    //
    private string _searchVal1 = string.Empty;
    public string SearchVal1
    {
        get { return _searchVal1; }
        set { _searchVal1 = value; OnPropertyChanged(nameof(SearchVal1)); }
    }

    private string _searchVal2 = string.Empty;
    public string SearchVal2
    {
        get { return _searchVal2; }
        set { _searchVal2 = value; OnPropertyChanged(nameof(SearchVal2)); }
    }

    private string _searchVal3 = string.Empty;
    public string SearchVal3
    {
        get { return _searchVal3; }
        set { _searchVal3 = value; OnPropertyChanged(nameof(SearchVal3)); }
    }
    //
    public RelCom SearchCommand { get; private set; }
    public RelCom OpenFiCommand { get; private set; }
    //
    private SearchResult selResult;
    public SearchResult SelResult
    {
        get { return selResult; }
        set { selResult = value; OnPropertyChanged(nameof(SelResult)); }
    }
    //
    #endregion


    public CsvViewModel()
    {
        ResList = new List<SearchResult>();
        OcResults = new ObservableCollection<SearchResult>();
        SearchCommand = new RelCom(Search_CanExecute, Search);
        OpenFiCommand = new RelCom(OpenFi_CanExecute, OpenFile);
    }


    private bool Search_CanExecute(object obj)
    {
        return true;
    }

    private void Search(object obj)
    {
        CurDir = string.Empty;
        //
        if (!string.IsNullOrWhiteSpace(SearchVal1))
            SearchVal2 = SearchVal1.Trim() + " " + SearchVal2.Trim();
        //
        if (!string.IsNullOrWhiteSpace(SearchVal3))
            SearchVal3 = SearchVal3.Trim();
        //
        try
        {
            TraverseTreeParallelForEach(@"\\ast-sigmanest\Feedback\Feedback", (f) =>
            {
                // Exceptions are no-ops.
                try
                {
                    // Do nothing with the data except read it to find string...
                    FileInfo fi1 = new FileInfo(f);
                    bool addfi = false;
                    //
                    string[] Lines = File.ReadAllLines(f);
                    List<string> refLines = new List<string>();
                    foreach (string line in Lines)
                    {
                        if (line.Contains(SearchVal2) & line.Contains(SearchVal3))
                        {
                            addfi = true;
                            refLines.Add(line);
                        }
                    }
                    //
                    if (addfi)
                    {
                        SearchResult Sres = new SearchResult { Dir = fi1.Directory.ToString(), FiName = fi1.Name, FiPath = fi1.FullName, Refs = refLines };
                        ResList.Add(Sres);
                    }
                    //
                    //contents = null;
                    Lines = null;
                    fi1 = null;
                    //
                }
                catch (FileNotFoundException) { }
                catch (IOException) { }
                catch (UnauthorizedAccessException) { }
                catch (SecurityException) { }
                // Display the filename.
                //Console.WriteLine(f);
            });
        }
        catch (ArgumentException Ae)
        {
            MessageBox.Show(Ae.Message);
        }
        //
        var resgrp = (from res in ResList group res by res.Dir into newres orderby newres.Key select newres);
        foreach (var rgrp in resgrp)
        {
            foreach (var res in rgrp)
            {
                OcResults.Add(res);
            }
        }
        //
    }


    private bool OpenFi_CanExecute(object obj)
    {
        return obj != null;
    }

    private void OpenFile(object obj)
    {
        Process.Start(new ProcessStartInfo(SelResult.FiPath));
    }


    public void TraverseTreeParallelForEach(string root, Action<string> action)
    {
        //Count of files traversed and timer for diagnostic output
        fileCount = 0;
        sw = Stopwatch.StartNew();

        // Determine whether to parallelize file processing on each folder based on processor count.
        int procCount = System.Environment.ProcessorCount;

        // Data structure to hold names of subfolders to be examined for files.
        Stack<string> dirs = new Stack<string>();

        if (!Directory.Exists(root))
        {
            throw new ArgumentException();
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs = { };
            string[] files = { };

            try
            {
                subDirs = Directory.GetDirectories(currentDir);
                // Push the subdirectories onto the stack for traversal.
                // This could also be done before handing the files.
                foreach (string str in subDirs)
                    dirs.Push(str);
            }
            // Thrown if we do not have discovery permission on the directory.
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Thrown if another process has deleted the directory after we retrieved its name.
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            try
            {
                files = Directory.GetFiles(currentDir, "*.csv");
            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (IOException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            // Execute in parallel if there are enough files in the directory.
            // Otherwise, execute sequentially.Files are opened and processed
            // synchronously but this could be modified to perform async I/O.
            try
            {
                if (files.Length < procCount)
                {
                    foreach (var file in files)
                    {
                        action(file);
                        fileCount++;
                    }
                }
                else
                {
                    Parallel.ForEach(files, () => 0, (file, loopState, localCount) =>
                    {
                        action(file);
                        return (int)++localCount;
                    },
                                     (c) =>
                                     {
                                         Interlocked.Add(ref fileCount, c);
                                     });
                }
            }
            catch (AggregateException ae)
            {
                ae.Handle((ex) =>
                {
                    if (ex is UnauthorizedAccessException)
                    {
                        // Here we just output a message and go on.
                        Console.WriteLine(ex.Message);
                        return true;
                    }
                    // Handle other exceptions here if necessary...

                    return false;
                });
            }
            //
        }
        //
    }
}

由于某种原因,数据模板中的按钮不会触发命令,即使它显示为绑定到它。任何帮助表示赞赏。谢谢。

标签: c#wpfmvvm

解决方案


您需要让 Open 命令知道 CanExecute 条件已更改,在您的SelResult设置器中执行此操作:

((RelayCommand<object>)OpenFiCommand).RaiseCanExecuteChanged();

这是我不喜欢使用的原因之一CanExecute


推荐阅读