Truyền hai tham số lệnh bằng liên kết WPF


155

Tôi có một lệnh mà tôi đang thực thi từ tệp XAML của mình bằng cú pháp tiêu chuẩn sau:

<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand}"/>

Điều này hoạt động tốt cho đến khi tôi nhận ra rằng tôi cần HAI mẩu thông tin từ chế độ xem để làm cho thao tác này hoàn thành theo cách người dùng mong đợi (chiều rộng và chiều cao của khung vẽ một cách cụ thể).

Có vẻ như có thể truyền một mảng làm đối số cho lệnh của tôi, nhưng tôi không thấy có cách nào để chỉ định ràng buộc cho hai thuộc tính canvas của tôi trong CommandParameter:

<Button Content="Zoom" 
        Command="{Binding MyViewModel.ZoomCommand" 
        CommandParameter="{Binding ElementName=MyCanvas, Path=Width}"/>

Làm cách nào để chuyển cả Chiều rộng và Chiều cao cho lệnh của tôi? Có vẻ như điều này là không thể khi sử dụng các lệnh từ XAML và tôi cần kết nối một trình xử lý nhấp chuột trong cơ sở mã của mình để có được thông tin này để chuyển sang phương thức thu phóng của tôi.


[ stackoverflow.com/questions/58114752/ chúc giải pháp trên. Tôi đã có cùng một vấn đề.)
user1482689

Câu trả lời:


240

Thứ nhất, nếu bạn đang thực hiện MVVM, thông thường bạn sẽ có sẵn thông tin này cho máy ảo của mình thông qua các thuộc tính riêng biệt bị ràng buộc khỏi chế độ xem. Điều đó giúp bạn tiết kiệm tất cả các tham số cho các lệnh của bạn.

Tuy nhiên, bạn cũng có thể đa liên kết và sử dụng trình chuyển đổi để tạo các tham số:

<Button Content="Zoom" Command="{Binding MyViewModel.ZoomCommand">
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource YourConverter}">
             <Binding Path="Width" ElementName="MyCanvas"/>
             <Binding Path="Height" ElementName="MyCanvas"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

Trong trình chuyển đổi của bạn:

public class YourConverter : IMultiValueConverter
{
    public object Convert(object[] values, ...)
    {
        return values.Clone();
    }

    ...
}

Sau đó, trong logic thực thi lệnh của bạn:

public void OnExecute(object parameter)
{
    var values = (object[])parameter;
    var width = (double)values[0];
    var height = (double)values[1];
}

1
Cảm ơn Kent - đó chính xác là những gì tôi đang tìm kiếm. Tôi thích cách tiếp cận đầu tiên của bạn tốt hơn để VM biết "trạng thái" của chế độ xem thông qua một ràng buộc mà không cần tôi phải truyền tham số nào cả, nhưng tôi vẫn có thể kiểm tra nó. Tôi không chắc chắn rằng điều đó sẽ làm việc cho tôi ở đây, vì tôi cần chế độ xem để làm cho khung vẽ càng lớn càng tốt và chuyển giá trị này cho VM. Nếu tôi liên kết nó, tôi sẽ không phải đặt chiều rộng trong VM chứ? Trong trường hợp nào, VM bị ràng buộc với khung nhìn?
JasonD

@Jason: bạn có thể làm một trong hai cách. Nghĩa là, có các thay đổi đẩy chế độ xem trở lại mô hình chế độ xem hoặc có các thay đổi đẩy mô hình chế độ xem đối với chế độ xem. Một ràng buộc TwoWay sẽ dẫn đến một trong hai tùy chọn có sẵn cho bạn.
Kent Boogaart

trong chương trình của tôi, tham số phương thức OnExecute là một mảng có giá trị null nhưng, trong trình chuyển đổi, các giá trị như mong đợi
Alex David

2
Tôi thấy tham số đó là null trong phương thức OnExecute, còn YourConverter.Convert () không được gọi sau khi nhấp vào nút. Tại sao?
Tàu

3
Điều này không hoạt động, khi nhấn nút, các tham số là null
adminSoftDK

38

Trong trình chuyển đổi của giải pháp đã chọn, bạn nên thêm giá trị.Clone () nếu không các tham số trong lệnh kết thúc null

public class YourConverter : IMultiValueConverter
{
    public object Convert(object[] values, ...)
    {
        return values.Clone();
    }

    ...
}

6
Xin chào, sự bổ sung này với Clone () làm cho nó hoạt động :) Bạn có thể giải thích, nó có gì khác biệt không. Tôi không hiểu tại sao nó cần Clone () để làm việc? Cảm ơn bạn.
adminSoftDK

Tôi có thể sai, nhưng đây (dòng 1267) trông giống như nó có thể là lý do để tôi: referencesource.microsoft.com/#PresentationFramework/src/...
maxp

14

Sử dụng Tuple trong Converter và trong OnExecute, chuyển đối tượng tham số trở lại Tuple.

public class YourConverter : IMultiValueConverter 
{      
    public object Convert(object[] values, ...)     
    {   
        Tuple<string, string> tuple = new Tuple<string, string>(
            (string)values[0], (string)values[1]);
        return (object)tuple;
    }      
} 

// ...

public void OnExecute(object parameter) 
{
    var param = (Tuple<string, string>) parameter;
}

5

Nếu giá trị của bạn là tĩnh, bạn có thể sử dụng x:Array:

<Button Command="{Binding MyCommand}">10
  <Button.CommandParameter>
    <x:Array Type="system:Object">
       <system:String>Y</system:String>
       <system:Double>10</system:Double>
    </x:Array>
  </Button.CommandParameter>
</Button>

" Nếu giá trị của bạn là tĩnh ": Tài nguyên tĩnh là gì? Ví dụ: câu hỏi đề cập đến Chiều rộng và Chiều cao Canvas. Những giá trị này không phải là hằng số, nhưng chúng có tĩnh không? XAML sẽ là gì trong trường hợp này?
phút

2
Tôi nên đã viết "hằng" thay vì "tĩnh". Tài nguyên tĩnh là tài nguyên không thay đổi trong quá trình thực thi. Nếu bạn sử dụng SystemColorschẳng hạn, bạn nên sử dụng DynamicResourcethay StaticResourcevì vì người dùng có thể thay đổi màu hệ thống thông qua Bảng điều khiển trong quá trình thực thi. Canvas WidthHeightkhông phải là tài nguyên và không tĩnh. Có các thuộc tính thể hiện được kế thừa từ FrameworkElement.
Tối đa

2

Về việc sử dụng Tuple trong Trình chuyển đổi, sẽ tốt hơn nếu sử dụng 'đối tượng' thay vì 'chuỗi', để nó hoạt động cho tất cả các loại đối tượng mà không giới hạn đối tượng 'chuỗi'.

public class YourConverter : IMultiValueConverter 
{      
    public object Convert(object[] values, ...)     
    {   
        Tuple<object, object> tuple = new Tuple<object, object>(values[0], values[1]);
        return tuple;
    }      
} 

Sau đó, logic thực thi trong Command có thể như thế này

public void OnExecute(object parameter) 
{
    var param = (Tuple<object, object>) parameter;

    // e.g. for two TextBox object
    var txtZip = (System.Windows.Controls.TextBox)param.Item1;
    var txtCity = (System.Windows.Controls.TextBox)param.Item2;
}

và đa liên kết với trình chuyển đổi để tạo các tham số (với hai đối tượng TextBox)

<Button Content="Zip/City paste" Command="{Binding PasteClick}" >
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource YourConvert}">
            <Binding ElementName="txtZip"/>
            <Binding ElementName="txtCity"/>
        </MultiBinding>
    </Button.CommandParameter>
</Button>

Tôi thích cái này vì nó rõ ràng hơn có bao nhiêu tham số bộ chuyển đổi hỗ trợ. Tốt cho chỉ hai tham số! (Thêm vào đó bạn đã hiển thị XAML và chức năng thực thi Lệnh để được bảo hiểm đầy đủ)
Caleb W.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.