web-dev-qa-db-ja.com

EventArgsをコマンドパラメーターとして渡すMVVM

Microsoft Expression Blend 4を使用しています
ブラウザを持っています..、

[XAML]ConnectionView "空のコードビハインド"

        <WebBrowser local:AttachedProperties.BrowserSource="{Binding Source}">
            <i:Interaction.Triggers>
                <i:EventTrigger>
                    <i:InvokeCommandAction Command="{Binding LoadedEvent}"/>
                </i:EventTrigger>
                <i:EventTrigger EventName="Navigated">
                    <i:InvokeCommandAction Command="{Binding NavigatedEvent}" CommandParameter="??????"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </WebBrowser>  

[C#]AttachedPropertiesクラス

public static class AttachedProperties
    {
        public static readonly DependencyProperty BrowserSourceProperty = DependencyProperty . RegisterAttached ( "BrowserSource" , typeof ( string ) , typeof ( AttachedProperties ) , new UIPropertyMetadata ( null , BrowserSourcePropertyChanged ) );

        public static string GetBrowserSource ( DependencyObject _DependencyObject )
        {
            return ( string ) _DependencyObject . GetValue ( BrowserSourceProperty );
        }

        public static void SetBrowserSource ( DependencyObject _DependencyObject , string Value )
        {
            _DependencyObject . SetValue ( BrowserSourceProperty , Value );
        }

        public static void BrowserSourcePropertyChanged ( DependencyObject _DependencyObject , DependencyPropertyChangedEventArgs _DependencyPropertyChangedEventArgs )
        {
            WebBrowser _WebBrowser = _DependencyObject as WebBrowser;
            if ( _WebBrowser != null )
            {
                string URL = _DependencyPropertyChangedEventArgs . NewValue as string;
                _WebBrowser . Source = URL != null ? new Uri ( URL ) : null;
            }
        }
    }

[C#]ConnectionViewModelクラス

public class ConnectionViewModel : ViewModelBase
    {
            public string Source
            {
                get { return Get<string> ( "Source" ); }
                set { Set ( "Source" , value ); }
            }

            public void Execute_ExitCommand ( )
            {
                Application . Current . Shutdown ( );
            }

            public void Execute_LoadedEvent ( )
            {
                MessageBox . Show ( "___Execute_LoadedEvent___" );
                Source = ...... ;
            }

            public void Execute_NavigatedEvent ( )
            {
                MessageBox . Show ( "___Execute_NavigatedEvent___" );
            }
    }

[C#]ViewModelBaseクラスここ

最後に :
コマンドとのバインドはうまく機能し、メッセージボックスが表示されます


私の質問:
ナビゲートされたイベントが発生したときにコマンドパラメーターとしてNavigationEventArgsを渡す方法

59
Ahmed Ghoneim

簡単にサポートされていません。 記事 にEventArgsをコマンドパラメーターとして渡す方法の説明があります。

MVVMLight を使用して調べることもできます。コマンドでEventArgsを直接サポートします。あなたの状況は次のようになります。

 <i:Interaction.Triggers>
    <i:EventTrigger EventName="Navigated">
        <cmd:EventToCommand Command="{Binding NavigatedEvent}"
            PassEventArgsToCommand="True" />
    </i:EventTrigger>
 </i:Interaction.Triggers>
61
E.Z. Hart

依存関係を最小限に抑えようとするため、MVVMLightのEventToCommandを使用する代わりに、これを自分で実装しました。これまでのところうまくいきますが、フィードバックは大歓迎です。

Xaml:

<i:Interaction.Behaviors>
    <beh:EventToCommandBehavior Command="{Binding DropCommand}" Event="Drop" PassArguments="True" />
</i:Interaction.Behaviors>

ViewModel:

public ActionCommand<DragEventArgs> DropCommand { get; private set; }

this.DropCommand = new ActionCommand<DragEventArgs>(OnDrop);

private void OnDrop(DragEventArgs e)
{
    // ...
}

EventToCommandBehavior:

/// <summary>
/// Behavior that will connect an UI event to a viewmodel Command,
/// allowing the event arguments to be passed as the CommandParameter.
/// </summary>
public class EventToCommandBehavior : Behavior<FrameworkElement>
{
    private Delegate _handler;
    private EventInfo _oldEvent;

    // Event
    public string Event { get { return (string)GetValue(EventProperty); } set { SetValue(EventProperty, value); } }
    public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(string), typeof(EventToCommandBehavior), new PropertyMetadata(null, OnEventChanged));

    // Command
    public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommandBehavior), new PropertyMetadata(null));

    // PassArguments (default: false)
    public bool PassArguments { get { return (bool)GetValue(PassArgumentsProperty); } set { SetValue(PassArgumentsProperty, value); } }
    public static readonly DependencyProperty PassArgumentsProperty = DependencyProperty.Register("PassArguments", typeof(bool), typeof(EventToCommandBehavior), new PropertyMetadata(false));


    private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var beh = (EventToCommandBehavior)d;

        if (beh.AssociatedObject != null) // is not yet attached at initial load
            beh.AttachHandler((string)e.NewValue);
    }

    protected override void OnAttached()
    {
        AttachHandler(this.Event); // initial set
    }

    /// <summary>
    /// Attaches the handler to the event
    /// </summary>
    private void AttachHandler(string eventName)
    {
        // detach old event
        if (_oldEvent != null)
            _oldEvent.RemoveEventHandler(this.AssociatedObject, _handler);

        // attach new event
        if (!string.IsNullOrEmpty(eventName))
        {
            EventInfo ei = this.AssociatedObject.GetType().GetEvent(eventName);
            if (ei != null)
            {
                MethodInfo mi = this.GetType().GetMethod("ExecuteCommand", BindingFlags.Instance | BindingFlags.NonPublic);
                _handler = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);
                ei.AddEventHandler(this.AssociatedObject, _handler);
                _oldEvent = ei; // store to detach in case the Event property changes
            }
            else
                throw new ArgumentException(string.Format("The event '{0}' was not found on type '{1}'", eventName, this.AssociatedObject.GetType().Name));
        }
    }

    /// <summary>
    /// Executes the Command
    /// </summary>
    private void ExecuteCommand(object sender, EventArgs e)
    {
        object parameter = this.PassArguments ? e : null;
        if (this.Command != null)
        {
            if (this.Command.CanExecute(parameter))
                this.Command.Execute(parameter);
        }
    }
}

ActionCommand:

public class ActionCommand<T> : ICommand
{
    public event EventHandler CanExecuteChanged;
    private Action<T> _action;

    public ActionCommand(Action<T> action)
    {
        _action = action;
    }

    public bool CanExecute(object parameter) { return true; }

    public void Execute(object parameter)
    {
        if (_action != null)
        {
            var castParameter = (T)Convert.ChangeType(parameter, typeof(T));
            _action(castParameter);
        }
    }
}
40
Mike Fuchs

私はいつも答えを求めてここに戻ってきたので、簡単な短いものを作りたいと思いました。

これを行うには複数の方法があります。

1. WPFツールを使用します。最も簡単です。

名前空間を追加します。

  • System.Windows.Interactivitiy
  • Microsoft.Expression.Interactions

XAML:

EventNameを使用して目的のイベントを呼び出し、MethodMethodName名を指定します。

<Window>
    xmlns:wi="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity"
    xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions">

    <wi:Interaction.Triggers>
        <wi:EventTrigger EventName="SelectionChanged">
            <ei:CallMethodAction
                TargetObject="{Binding}"
                MethodName="ShowCustomer"/>
        </wi:EventTrigger>
    </wi:Interaction.Triggers>
</Window>

コード:

public void ShowCustomer()
{
    // Do something.
}

2. MVVMLightを使用します。最も困難。

GalaSoft NuGetパッケージをインストールします。

enter image description here

名前空間を取得します。

  • System.Windows.Interactivity
  • GalaSoft.MvvmLight.Platform

XAML:

EventNameを使用して目的のイベントを呼び出し、Command名をバインディングに指定します。メソッドの引数を渡したい場合は、PassEventArgsToCommandをtrueにマークします。

<Window>
    xmlns:wi="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity"
    xmlns:cmd="http://www.galasoft.ch/mvvmlight">

    <wi:Interaction.Triggers>
       <wi:EventTrigger EventName="Navigated">
           <cmd:EventToCommand Command="{Binding CommandNameHere}"
               PassEventArgsToCommand="True" />
       </wi:EventTrigger>
    </wi:Interaction.Triggers>
</Window>

デリゲートを実装するコード: Source

このためには、Prism MVVM NuGetパッケージを入手する必要があります。

enter image description here

using Microsoft.Practices.Prism.Commands;

// With params.
public DelegateCommand<string> CommandOne { get; set; }
// Without params.
public DelegateCommand CommandTwo { get; set; }

public MainWindow()
{
    InitializeComponent();

    // Must initialize the DelegateCommands here.
    CommandOne = new DelegateCommand<string>(executeCommandOne);
    CommandTwo = new DelegateCommand(executeCommandTwo);
}

private void executeCommandOne(string param)
{
    // Do something here.
}

private void executeCommandTwo()
{
    // Do something here.
}

DelegateCommandなしのコード: ソース

using GalaSoft.MvvmLight.CommandWpf

public MainWindow()
{
    InitializeComponent();

    CommandOne = new RelayCommand<string>(executeCommandOne);
    CommandTwo = new RelayCommand(executeCommandTwo);
}

public RelayCommand<string> CommandOne { get; set; }

public RelayCommand CommandTwo { get; set; }

private void executeCommandOne(string param)
{
    // Do something here.
}

private void executeCommandTwo()
{
    // Do something here.
}

3. Telerik EventToCommandBehavior を使用します。これはオプションです。

NuGetパッケージ をダウンロードする必要があります。

XAML

<i:Interaction.Behaviors>
    <telerek:EventToCommandBehavior
         Command="{Binding DropCommand}"
         Event="Drop"
         PassArguments="True" />
</i:Interaction.Behaviors>

コード:

public ActionCommand<DragEventArgs> DropCommand { get; private set; }

this.DropCommand = new ActionCommand<DragEventArgs>(OnDrop);

private void OnDrop(DragEventArgs e)
{
    // Do Something
}
19
AzzamAziz

これはかなり古い質問であることはわかっていますが、今日同じ問題にぶつかり、MVVMLightのすべてを参照することにあまり興味がなかったので、イベント引数でイベントトリガーを使用できます。過去にMVVMLightを使用しましたが、これはすばらしいフレームワークですが、プロジェクトに使用したくないだけです。

この問題を解決するために行ったのは、[〜#〜] ultra [〜#〜]最小限、[〜#〜] extremely [〜#〜]適応可能なカスタムを作成することでした。コマンドにバインドし、コマンドのCanExecuteおよびExecute関数に引数を渡すイベント引数コンバーターを提供できるトリガーアクション。イベントargsを逐語的に渡すことは望ましくありません。これにより、ビューレイヤータイプがビューモデルレイヤーに送信されることになります(MVVMでは発生しません)。

ここに私が思いついたEventCommandExecuterクラスがあります:

public class EventCommandExecuter : TriggerAction<DependencyObject>
{
    #region Constructors

    public EventCommandExecuter()
        : this(CultureInfo.CurrentCulture)
    {
    }

    public EventCommandExecuter(CultureInfo culture)
    {
        Culture = culture;
    }

    #endregion

    #region Properties

    #region Command

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommandExecuter), new PropertyMetadata(null));

    #endregion

    #region EventArgsConverterParameter

    public object EventArgsConverterParameter
    {
        get { return (object)GetValue(EventArgsConverterParameterProperty); }
        set { SetValue(EventArgsConverterParameterProperty, value); }
    }

    public static readonly DependencyProperty EventArgsConverterParameterProperty =
        DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(EventCommandExecuter), new PropertyMetadata(null));

    #endregion

    public IValueConverter EventArgsConverter { get; set; }

    public CultureInfo Culture { get; set; }

    #endregion

    protected override void Invoke(object parameter)
    {
        var cmd = Command;

        if (cmd != null)
        {
            var param = parameter;

            if (EventArgsConverter != null)
            {
                param = EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.InvariantCulture);
            }

            if (cmd.CanExecute(param))
            {
                cmd.Execute(param);
            }
        }
    }
}

このクラスには2つの依存関係プロパティがあり、1つはビューモデルのコマンドへのバインドを許可し、もう1つはイベント引数の変換中に必要な場合にイベントのソースをバインドできます。必要に応じて、カルチャ設定を提供することもできます(デフォルトでは現在のUIカルチャになります)。

このクラスを使用すると、ビューモデルのコマンドロジックで消費されるようにイベント引数を調整できます。ただし、イベント引数をそのまま渡す場合は、イベント引数コンバータを指定しないでください。

XAMLでのこのトリガーアクションの最も簡単な使用法は次のとおりです。

<i:Interaction.Triggers>
    <i:EventTrigger EventName="NameChanged">
        <cmd:EventCommandExecuter Command="{Binding Path=Update, Mode=OneTime}" EventArgsConverter="{x:Static c:NameChangedArgsToStringConverter.Default}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

イベントのソースへのアクセスが必要な場合は、イベントの所有者にバインドします

<i:Interaction.Triggers>
    <i:EventTrigger EventName="NameChanged">
        <cmd:EventCommandExecuter 
            Command="{Binding Path=Update, Mode=OneTime}" 
            EventArgsConverter="{x:Static c:NameChangedArgsToStringConverter.Default}"
            EventArgsConverterParameter="{Binding ElementName=SomeEventSource, Mode=OneTime}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

(これは、トリガーをアタッチするXAMLノードにx:Name="SomeEventSource"が割り当てられていることを前提としています

このXAMLは、いくつかの必要な名前空間のインポートに依存しています

xmlns:cmd="clr-namespace:MyProject.WPF.Commands"
xmlns:c="clr-namespace:MyProject.WPF.Converters"
xmlns:i="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity"

IValueConverter(この場合はNameChangedArgsToStringConverterと呼ばれる)を作成して、実際の変換ロジックを処理します。基本的なコンバーターの場合、通常はデフォルトのstatic readonlyコンバーターインスタンスを作成します。その後、上記のようにXAMLで直接参照できます。

このソリューションの利点は、プロジェクトに単一のクラスを追加するだけで、InvokeCommandActionで使用するのとほぼ同じ方法で対話フレームワークを使用できることです。単一のクラス(約75行)を追加することは、同じ結果を達成するためにライブラリ全体よりもはるかに望ましいはずです。

[〜#〜] note [〜#〜]

これは@adabyronからの回答に多少似ていますが、動作の代わりにイベントトリガーを使用します。このソリューションは、イベント引数の変換機能も提供しますが、@ adabyronのソリューションもこれを実行できませんでした。私は本当にトリガーを行動よりも好む理由はありません。個人的な選択です。 IMOのどちらの戦略も合理的な選択です。

12
pjs

この投稿を見つけたばかりの人のために、新しいバージョン(このトピックでは公式ドキュメントがスリムであるため正確なバージョンは不明)では、CommandParameterが指定されていない場合、InvokeCommandActionのデフォルトの動作はCommandParameterとしてアタッチされるイベント。したがって、オリジナルのポスターのXAMLは次のように簡単に記述できます。

<i:Interaction.Triggers>
  <i:EventTrigger EventName="Navigated">
    <i:InvokeCommandAction Command="{Binding NavigatedEvent}"/>
  </i:EventTrigger>
</i:Interaction.Triggers>

その後、コマンドで、タイプNavigationEventArgs(または適切なイベント引数タイプ)のパラメーターを受け入れると、自動的に提供されます。

12
joshb

Joshbがすでに述べたことに追加する-これは私にとってはうまく機能します。必ずMicrosoft.Expression.Interactions.dllおよびSystem.Windows.Interactivity.dllへの参照を追加し、xamlで以下を実行してください。

    xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"

私は自分のニーズのためにこのようなものを使用することになりました。これは、カスタムパラメータを渡すこともできることを示しています。

<i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">

                <i:InvokeCommandAction Command="{Binding Path=DataContext.RowSelectedItem, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 
                                       CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
            </i:EventTrigger>
</i:Interaction.Triggers>
5
EbbnFlow

InvokeCommandActionで簡単にできるとは思わない-MVVMLightなどから EventToCommand を見てみよう。

3
Tim

Blend for Visual Studio 2013の動作とアクションでは、InvokeCommandActionを使用できます。 Dropイベントでこれを試しましたが、XAMLでCommandParameterが指定されていませんでしたが、驚いたことに、Execute ActionパラメーターにはDragEventArgsが含まれていました。これは他のイベントでも起こると思いますが、テストしていません。

1
OzFrog

InvokeCommandActionが設定されていない場合、PrismのCommandParameterはデフォルトでイベント引数を渡します。

https://docs.Microsoft.com/en-us/previous-versions/msp-n-p/gg405494(v = pandp.40)#passing-eventargs-parameters-to-the-command

以下に例を示します。 prism:InvokeCommandActionの代わりにi:InvokeCommandActionを使用していることに注意してください。

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Sorting">
        <prism:InvokeCommandAction Command="{Binding SortingCommand}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>
1
datchung

これは、漏れやすいEventArgs抽象化を防ぐ@adabyronの回答のバージョンです。

まず、変更されたEventToCommandBehaviorクラス(現在は汎用抽象クラスであり、ReSharperコードクリーンアップでフォーマットされています)。新しいGetCommandParameter仮想メソッドとそのデフォルトの実装に注意してください。

public abstract class EventToCommandBehavior<TEventArgs> : Behavior<FrameworkElement>
    where TEventArgs : EventArgs
{
    public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(string), typeof(EventToCommandBehavior<TEventArgs>), new PropertyMetadata(null, OnEventChanged));
    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommandBehavior<TEventArgs>), new PropertyMetadata(null));
    public static readonly DependencyProperty PassArgumentsProperty = DependencyProperty.Register("PassArguments", typeof(bool), typeof(EventToCommandBehavior<TEventArgs>), new PropertyMetadata(false));
    private Delegate _handler;
    private EventInfo _oldEvent;

    public string Event
    {
        get { return (string)GetValue(EventProperty); }
        set { SetValue(EventProperty, value); }
    }

    public ICommand Command
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public bool PassArguments
    {
        get { return (bool)GetValue(PassArgumentsProperty); }
        set { SetValue(PassArgumentsProperty, value); }
    }

    protected override void OnAttached()
    {
        AttachHandler(Event);
    }

    protected virtual object GetCommandParameter(TEventArgs e)
    {
        return e;
    }

    private void AttachHandler(string eventName)
    {
        _oldEvent?.RemoveEventHandler(AssociatedObject, _handler);

        if (string.IsNullOrEmpty(eventName))
        {
            return;
        }

        EventInfo eventInfo = AssociatedObject.GetType().GetEvent(eventName);

        if (eventInfo != null)
        {
            MethodInfo methodInfo = typeof(EventToCommandBehavior<TEventArgs>).GetMethod("ExecuteCommand", BindingFlags.Instance | BindingFlags.NonPublic);

            _handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, methodInfo);
            eventInfo.AddEventHandler(AssociatedObject, _handler);
            _oldEvent = eventInfo;
        }
        else
        {
            throw new ArgumentException($"The event '{eventName}' was not found on type '{AssociatedObject.GetType().FullName}'.");
        }
    }

    private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = (EventToCommandBehavior<TEventArgs>)d;

        if (behavior.AssociatedObject != null)
        {
            behavior.AttachHandler((string)e.NewValue);
        }
    }

    // ReSharper disable once UnusedMember.Local
    // ReSharper disable once UnusedParameter.Local
    private void ExecuteCommand(object sender, TEventArgs e)
    {
        object parameter = PassArguments ? GetCommandParameter(e) : null;

        if (Command?.CanExecute(parameter) == true)
        {
            Command.Execute(parameter);
        }
    }
}

次に、DragCompletedEventArgsを隠す派生クラスの例。一部の人々は、ビューモデルアセンブリにEventArgs抽象化が漏れることに懸念を表明しました。これを防ぐために、重要な値を表すインターフェイスを作成しました。インターフェイスは、UIアセンブリのプライベート実装を使用して、ビューモデルアセンブリ内に配置できます。

// UI Assembly
public class DragCompletedBehavior : EventToCommandBehavior<DragCompletedEventArgs>
{
    protected override object GetCommandParameter(DragCompletedEventArgs e)
    {
        return new DragCompletedArgs(e);
    }

    private class DragCompletedArgs : IDragCompletedArgs
    {
        public DragCompletedArgs(DragCompletedEventArgs e)
        {
            Canceled = e.Canceled;
            HorizontalChange = e.HorizontalChange;
            VerticalChange = e.VerticalChange;
        }

        public bool Canceled { get; }
        public double HorizontalChange { get; }
        public double VerticalChange { get; }
    }
}

// View model Assembly
public interface IDragCompletedArgs
{
    bool Canceled { get; }
    double HorizontalChange { get; }
    double VerticalChange { get; }
}

@adabyronの答えと同様に、コマンドパラメーターをIDragCompletedArgsにキャストします。

0
NathanAldenSr

私がすることは、InvokeCommandActionを使用してコントロールのロードされたイベントをビューモデルのコマンドにバインドし、Xamlのコントロールax:Nameを与えてCommandParameterとして渡し、次にロードされたコマンドフックビューモデルハンドラーで必要なイベントまでイベント引数を取得します。

0
DRL

@Mike Fuchsの回答を参考に、さらに小さなソリューションを紹介します。ボイラープレートの一部を減らすためにFody.AutoDependencyPropertyMarkerを使用しています。

クラス

public class EventCommand : TriggerAction<DependencyObject>
{
    [AutoDependencyProperty]
    public ICommand Command { get; set; }

    protected override void Invoke(object parameter)
    {
        if (Command != null)
        {
            if (Command.CanExecute(parameter))
            {
                Command.Execute(parameter);
            }
        }
    }
}

EventArgs

public class VisibleBoundsArgs : EventArgs
{
    public Rect VisibleVounds { get; }

    public VisibleBoundsArgs(Rect visibleBounds)
    {
        VisibleVounds = visibleBounds;
    }
}

XAML

<local:ZoomableImage>
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="VisibleBoundsChanged" >
         <local:EventCommand Command="{Binding VisibleBoundsChanged}" />
      </i:EventTrigger>
   </i:Interaction.Triggers>
</local:ZoomableImage>

ViewModel

public ICommand VisibleBoundsChanged => _visibleBoundsChanged ??
                                        (_visibleBoundsChanged = new RelayCommand(obj => SetVisibleBounds(((VisibleBoundsArgs)obj).VisibleVounds)));
0
Ralt