Mauscursor für Textblock ändern

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 37 Antworten in diesem Thema. Der letzte Beitrag () ist von Amro.

    kafffee schrieb:

    VMIsBusy.

    Hört sich doch gut an.
    Ist das eine Property mit OnPropertyChanged im Setter dann kannst du die nehmen.
    NoFear hat warscheinlich schon vorrausgedacht...

    kafffee schrieb:

    So jetzt hats auch bei mir geschnaggelt, du willst mit nem Konverter dass Boolean IsBusy in einen Mauszeigertyp umwandeln oder?


    Jaaa, also erstmal .
    Dann machen wir das mit den integrierten BooleanToVisibilityConverter.

    Dann Sowas:
    Bilder
    • IsBusy.png

      16,75 kB, 1.340×696, 44 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Amro“ ()

    Hab ich vorhin gar nicht dran gedacht. Hab die Prop glaub auch nur ein Mal erst gebraucht aber danke für die Idee :)

    Hab das jetzt weil mir der Geduldsfaden gerissen ist und ich den Rest meiner Arbeit unbedingt noch durchprügeln wollte mit Code Behind gelöst. Man verzeihe mir lol.

    Ich hab in dem Projekttemplate von Nofear23m noch längst nicht alles durchschaut, bisher war ich immer nur froh dass es funzt.

    Ich schau nochmal genau nach wie das implementiert ist und meld mich dann nochmal :)
    @Amro

    Yep dassis mit RaisePropertyChanged :)

    VB.NET-Quellcode

    1. Private _isBusy As Boolean
    2. <JsonIgnore>
    3. Public Property VMisBusy As Boolean
    4. Get
    5. Return _isBusy
    6. End Get
    7. Set
    8. _isBusy = Value
    9. RaisePropertyChanged()
    10. End Set
    11. End Property


    Guck mal das hier:

    VB.NET-Quellcode

    1. Private _StarteBrennen As ICommand
    2. Public ReadOnly Property StarteBrennen() As ICommand
    3. Get
    4. If _StarteBrennen Is Nothing Then _StarteBrennen = New RelayCommand(AddressOf StarteBrennen_Execute, AddressOf StarteBrennen_CanExecute)
    5. Return _StarteBrennen
    6. End Get
    7. End Property
    8. Private Sub StarteBrennen_Execute(obj As Object)
    9. BrennenLaeuft = True
    10. MeinWMP.BurnCD(_DateienListe, _Laufwerk, _AlsDatenBrennen, _CDTitel)
    11. End Sub
    12. Private Function StarteBrennen_CanExecute(obj As Object) As Boolean
    13. Return Not BrennenLaeuft
    14. End Function
    15. End Class


    Da kannst du z.B. mit StarteBrennen_CanExecute den Button, der den Command ausführt, disablen... Aber wusstest du bestimmt schon...

    Das MultiProjectTemplate kannst du hier irgendwo auf VB Paradise runterladen wenns dich interessiert, ich habs jetzt aber leider net auf Anhieb gefunden...

    kafffee schrieb:

    Yep dassis mit RaisePropertyChanged


    Ja genau das ist die Property um deine langen Prozesse zu Checken.
    Kannst alle Methoden die was verabeiten mit bestücken.

    Am Anfang der Methode im ViewModel VMisBusy = true und am Ende auf false.
    Der rest macht das Binding und der Converter.

    Wenn du das verstanden hast machst du dir ein UserControl mit eine ProgressBar.
    Setzt das UserControl auf das Window oder ein anderes UserControl wo du es haben willst.
    UserControl Visibility = VMisBusy und fertig .
    Sowas halt:

    XML-Quellcode

    1. <UserControl x:Class="IsBusyTest.IBusyView"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:IsBusyTest"
    7. mc:Ignorable="d"
    8. Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}"
    9. Background="Transparent" >
    10. <Border Background="White" BorderBrush="Gainsboro"
    11. CornerRadius="10" Opacity="0.9" Width="450" Height="150">
    12. <Border.Effect>
    13. <DropShadowEffect BlurRadius="5" ShadowDepth="8" Opacity="0.5" />
    14. </Border.Effect>
    15. <StackPanel Margin="15" VerticalAlignment="Center">
    16. <TextBlock HorizontalAlignment="Center" Text="in arbeit..." Margin="5"/>
    17. <ProgressBar IsIndeterminate="{Binding IsBusy}" Height="25" Margin="10" />
    18. </StackPanel>
    19. </Border>
    20. </UserControl>


    Edit: Du hast noch den Vorteil wenn du es in ein Grid.Column setzt zum Beispiel,
    wird das dahinterliegende UserControl gespeert und kann nicht bedient werden. Wie ein art Dialog.
    Da aber der Background auf Transparent ist, sieht es der Benutzer nicht sondern nur die Border.
    Und wenn du dich noch etwas umschaust im Netz, findest du die geilsten Dinger als Template für die Progressbar.

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „Amro“ ()

    Ganz kurz. Der Command aus Post#24 ist kein RelayCommand, sondern ein … (spezifischer) Command. Ein RelayCommand ist (soweit ich bisher weiß) eine allgemeine Klasse, die ihre Funktionalität per DependencyInjection (?) erhält. Also: Du hast ne allgemeine, ICommand implementierende Klasse, die bei Execute eine Sub aufruft und bei CanExecute den Boolean-Wert einer Function wiedergibt. Aber welche Sub/Function das ist, das bestimmt das VM, indem sie eine spezifische RelayCommand-Instanz erschafft: Dim CdBrennenRelayCommand As New RelayCommand(AddressOf CdBrennen, Function(x) Not CdBrennenLäuftGerade(x)). Und das View bindet an diesen spezifischen VM-Command.
    CdBrennen und CdBrennenLäuftGerade muss bei diesem Konstrukt jeweils einen Object-Parameter haben, der durch den CommandParameter des GUI-Button festgelegt werden kann.
    Ein Beispiel hab ich in MVVM mit WinForms - kleiner Einstieg für Anfänger
    Die von mir derzeit verwendete RelayCommand-Klasse sieht so aus:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Class RelayCommand : Implements Windows.Input.ICommand
    2. Event CanExecuteChanged As EventHandler Implements Windows.Input.ICommand.CanExecuteChanged
    3. Private ReadOnly CommandAction As Action(Of Object)
    4. Private ReadOnly CanExecuteCommandAction As Func(Of Object, Boolean)
    5. Sub New(CommandAction As Action(Of Object))
    6. ArgumentNullException.ThrowIfNull(CommandAction, NameOf(CommandAction))
    7. Me.CommandAction = CommandAction
    8. End Sub
    9. Sub New(CommandAction As Action(Of Object), CanExecuteCommandAction As Func(Of Object, Boolean))
    10. ArgumentNullException.ThrowIfNull(CommandAction, NameOf(CommandAction))
    11. Me.CommandAction = CommandAction
    12. Me.CanExecuteCommandAction = CanExecuteCommandAction
    13. End Sub
    14. Function CanExecute(Parameter As Object) As Boolean Implements Windows.Input.ICommand.CanExecute
    15. Return CanExecuteCommandAction Is Nothing OrElse CanExecuteCommandAction.Invoke(Parameter)
    16. End Function
    17. Sub Execute(CommandParameter As Object) Implements Windows.Input.ICommand.Execute
    18. CommandAction(CommandParameter)
    19. End Sub
    20. Sub NotifyCanExecuteChanged()
    21. RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
    22. End Sub
    23. End Class

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ganz ehrlich bei mir Klappt das mit den CanExecute in diesem Fall nicht immer.
    Hab noch nicht raus warum.
    Hab es mit den ViewModelBase gelöst erstmal.
    Weiß nicht ob das gut ist.
    Hab das irgendwo Online aufgeschnappt:
    Spoiler anzeigen

    C#-Quellcode

    1. public class ViewModelBase : INotifyPropertyChanged
    2. {
    3. public event PropertyChangedEventHandler PropertyChanged;
    4. private bool _isBusy;
    5. public bool IsBusy
    6. {
    7. get { return _isBusy; }
    8. set
    9. {
    10. if (_isBusy != value)
    11. {
    12. _isBusy = value;
    13. NotBusy = !IsBusy;
    14. OnPropertyChanged(nameof(IsBusy));
    15. OnPropertyChanged(nameof(NotBusy));
    16. }
    17. }
    18. }
    19. public bool NotBusy { get; private set; }
    20. public ViewModelBase()
    21. {
    22. NotBusy = true;
    23. }
    24. protected virtual void OnPropertyChanged(string propertyName)
    25. {
    26. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    27. }
    28. }


    und in XAML:

    XML-Quellcode

    1. <Button Command="{Binding MYCommandAsync}" IsEnabled="{Binding NotBusy}" />

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Amro“ ()

    Dass es nicht immer mit CanExecute geht, das hatte VB1963 in dem Diskussionsthread erwähnt und wir hatten dort auch eine Ursache gefunden: Immer dann, wenn sich der Wert ändern könnte, muss man das vom VM aus dem View mitteilen, damit das View nochmal einen Blick draufwirft und eventuelle betroffene Controls de-/reaktiviert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ok, das funktionier bei mir auch .

    VaporiZed schrieb:

    Dass es nicht immer mit CanExecute geht, das hatte VB1963 in dem Diskussionsthread erwähnt und wir hatten dort auch eine Ursache gefunden: Immer dann, wenn sich der Wert ändern könnte, muss man das vom VM aus dem View mitteilen, damit das View nochmal einen Blick draufwirft und eventuelle betroffene Controls de-/reaktiviert.



    Hab noch eine Frage zum RelayCommand in dem Projekt.
    Was spricht dagegen in der Execute-Methode, die CanExecute am Ende nochmal aufzurufen.
    Ohne den Event CanExecuteChanged.
    Oder ist das falsch?

    So etwa:

    VB.NET-Quellcode

    1. Sub Execute(Parameter As Object) Implements System.Windows.Input.ICommand.Execute
    2. CommandAction()
    3. CanExecute(null)
    4. End Sub





    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Amro“ ()

    Was bringt Dir das? Das ist ja ein Funktionsaufruf. Die CanExecute-Methode soll doch nur ermitteln, ob z.B. der Button geklickt werden kann. Bei Dir würde das ja die Aktionen CdBrennenLäuft sein, die True zurückgibt. Und für CanExecute sagst Du: Return Not CdBrennenLäuft. Aber wenn Du das so machst, wie Du jetzt vorschlägst, bekommst Du ein True oder False an der Stelle zurück, mit dem Du noch nicht mal was anfängst. Den Aufruf kannst Du Dir also schenken.
    Das Programm nutzt CanExecute und CanExecuteChanged, um zu prüfen, ob z.B. ein Button geklickt werden kann oder nicht. Wenn sich der Wert geändert haben könnte, ruft man explizit CanExecuteChanged auf, damit das Progrmamm CanExecute aufruft und dessen Ergebnis hernimmt, um das GUI zu verändern.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    OK.
    Ich hab jetzt festgestellt das die Lösung auch nicht zuverlässig ist.
    Hab einen Generischen RelayCommand und da funktioniert das wieder nicht.
    Das einzige wo es bis jetzt immer funktioniert hat ist das MVVM.Toolkit.
    Ich glaube das ist auch das beste wenn mann seine ViewModels MVVM-Konform und Plattform unabhängig gestallten will.
    Sonst ist selbst das ICommad ein problem glaub ich.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Amro“ ()

    Upsi. Da hatte ich tatsächlich nicht gelesen, wer da schreibt. Dachte, es ist kafffee, daher schrieb ist was von »Deiner« CdBrennenLäuft-Methode :whistling:
    Was meinst Du mit »nicht zuverlässig«? Da ist ja vom Ablauf her keine Magie dabei. Ich ruf die Methode NotifyCanExecuteChanged des spezifischen RelayCommands auf, wenn es möglich ist, dass sich der Wert von CanExecute geändert haben könnte. Dadurch wird das RelayCommand-Event CanExecuteChanged abgefeuert und somit das View/GUI informiert, im Sinne von: »Ey, schau mal nach, ob sich für Dich was geändert hat.« Das View sieht, dass ein Button an den RelayCommand gebunden ist, ruft CanExecute des RelayCommands auf und setzt den Enabled-Status auf den Wert von dem, was CanExecute des RelayCommands zurückgibt. Kannst Du ein einfaches Beispiel(projekt) posten, bei dem es nicht klappt wie erhofft?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Amro schrieb:

    Hab einen Generischen RelayCommand und da funktioniert das wieder nicht.
    Das einzige wo es bis jetzt immer funktioniert hat ist das MVVM.Toolkit.

    Probier auch mal meine Version
    Spoiler anzeigen
    File RelayCommand.vb:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Namespace System.Windows.Input
    3. Public Class RelayCommand : Inherits CommandBase
    4. Private ReadOnly _execute As Action
    5. Private ReadOnly _canExecute As Func(Of Boolean) = Function() Enabled
    6. <DebuggerStepThrough()> _
    7. Public Sub New(ByVal execute As Action, Optional ByVal canExecute As Func(Of Boolean) = Nothing)
    8. If execute Is Nothing Then Throw New ArgumentNullException("execute")
    9. Me._execute = execute
    10. If canExecute.NotNull Then Me._canExecute = canExecute
    11. End Sub
    12. <DebuggerStepThrough()> _
    13. Public Overrides Function CanExecute(ByVal parameter As Object) As Boolean
    14. Return _canExecute()
    15. End Function
    16. <DebuggerStepThrough()> _
    17. Public Overrides Sub Execute(ByVal parameter As Object)
    18. Me._execute()
    19. End Sub
    20. End Class
    21. Public Class RelayCommand(Of T) : Inherits CommandBase
    22. Private ReadOnly _execute As Action(Of T)
    23. Private ReadOnly _canExecute As Predicate(Of T) = Function(itm As T) Enabled
    24. <DebuggerStepThrough()> _
    25. Public Sub New(ByVal execute As Action(Of T), Optional ByVal canExecute As Predicate(Of T) = Nothing)
    26. If execute Is Nothing Then Throw New ArgumentNullException("execute")
    27. Me._execute = execute
    28. If canExecute.NotNull Then Me._canExecute = canExecute
    29. End Sub
    30. <DebuggerStepThrough()> _
    31. Public Overrides Function CanExecute(ByVal parameter As Object) As Boolean
    32. Return _canExecute(DirectCast(parameter, T))
    33. End Function
    34. <DebuggerStepThrough()> _
    35. Public Overrides Sub Execute(ByVal parameter As Object)
    36. Me._execute(DirectCast(parameter, T))
    37. End Sub
    38. End Class
    39. Public MustInherit Class CommandBase : Inherits NotifyPropertyChanged : Implements ICommand
    40. Private EventDisabled As New Counter 'verhindert Ereigniskette beim gegenseitigen Aufruf von CanExecute und Setter der Enabled-Property
    41. 'das CanExecuteChanged-Event vereinigt sich mit dem statischen CommandManager.RequerySuggested-Event. Eiglich müsste es LaunchRequery heißen oderso
    42. Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    43. AddHandler(ByVal value As EventHandler)
    44. AddHandler CommandManager.RequerySuggested, value
    45. End AddHandler
    46. RemoveHandler(ByVal value As EventHandler)
    47. RemoveHandler CommandManager.RequerySuggested, value
    48. End RemoveHandler
    49. RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
    50. CommandManager.InvalidateRequerySuggested()
    51. End RaiseEvent
    52. End Event
    53. Public Shared ReadOnly EnabledChangedArgs As New PropertyChangedEventArgs("Enabled")
    54. Public MustOverride Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
    55. Public MustOverride Function CanExecute(ByVal parameter As Object) As Boolean
    56. Private _Enabled As Boolean = True
    57. Public Property Enabled() As Boolean
    58. Get
    59. Return _Enabled
    60. End Get
    61. Set(ByVal value As Boolean)
    62. If ChangePropIfDifferent(value, _Enabled, EnabledChangedArgs) Then
    63. If EventDisabled.Up = 0 Then RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
    64. EventDisabled.Down()
    65. End If
    66. End Set
    67. End Property
    68. Private Function ICanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
    69. If EventDisabled.Up = 0 Then Enabled = CanExecute(parameter)
    70. EventDisabled.Down()
    71. Return _Enabled
    72. End Function
    73. End Class
    74. End Namespace

    File NotifyPropertyChanged.vb:

    VB.NET-Quellcode

    1. Imports System.Runtime.CompilerServices
    2. Imports System.Reflection
    3. Imports System.Diagnostics
    4. 'Imports Helpers.BitOperation
    5. Namespace System.ComponentModel
    6. 'NotifyPropertyChanged
    7. <Serializable> _
    8. Public Class NotifyPropertyChanged : Implements INotifyPropertyChanged, ICloneable
    9. 'Wpf-Version: DesignerProperties.GetIsInDesignMode(DependancyObject)
    10. Private Shared _IsInDesignMode As Boolean? = Nothing
    11. Private Shared _HostProcesses As New List(Of String)({"XDesProc", "devenv", "WDExpress"})
    12. Public Shared ReadOnly Property IsInDesignMode() As Boolean
    13. Get
    14. If Not _IsInDesignMode.HasValue Then
    15. _IsInDesignMode = _HostProcesses.Contains(Process.GetCurrentProcess().ProcessName)
    16. End If
    17. Return _IsInDesignMode.Value
    18. End Get
    19. End Property
    20. Public Shared Sub MockDesignmodeAs(value As Boolean)
    21. _IsInDesignMode = value
    22. End Sub
    23. <NonSerialized> _
    24. Private _PropertyChanged As PropertyChangedEventHandler
    25. Public Custom Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    26. AddHandler(value As PropertyChangedEventHandler)
    27. _PropertyChanged = DirectCast([Delegate].Combine(_PropertyChanged, value), PropertyChangedEventHandler)
    28. End AddHandler
    29. RemoveHandler(value As PropertyChangedEventHandler)
    30. _PropertyChanged = DirectCast([Delegate].Remove(_PropertyChanged, value), PropertyChangedEventHandler)
    31. End RemoveHandler
    32. RaiseEvent(sender As Object, e As PropertyChangedEventArgs)
    33. If _PropertyChanged IsNot Nothing Then _PropertyChanged(sender, e)
    34. End RaiseEvent
    35. End Event
    36. Protected Function ChangePropIfDifferent(Of T)(value As T, ByRef backingField As T, <CallerMemberName> Optional name As String = "") As Boolean
    37. Return ChangePropIfDifferent(value, backingField, {New PropertyChangedEventArgs(name)})
    38. End Function
    39. Protected Function ChangePropIfDifferent(Of T)(value As T, ByRef backingField As T, ParamArray propNames() As String) As Boolean
    40. Return ChangePropIfDifferent(value, backingField, propNames.ToArray(Function(s) New PropertyChangedEventArgs(s)))
    41. End Function
    42. 'Protected Function ChangePropIfDifferent(Of T)(value As T, ByRef backingField As T, callbackIfChanged As Action) As Boolean
    43. ' If Object.Equals(backingField, value) Then Return False
    44. ' backingField = value
    45. ' callbackIfChanged()
    46. ' Return True
    47. 'End Function
    48. Protected Function ChangePropIfDifferent(Of T)(value As T, ByRef backingField As T, ParamArray props() As PropertyChangedEventArgs) As Boolean
    49. If Object.Equals(backingField, value) Then Return False
    50. backingField = value
    51. RaisePropChanged(props)
    52. Return True
    53. End Function
    54. Public Sub RaisePropChanged(Optional name As String = "")
    55. RaisePropChanged({New PropertyChangedEventArgs(name)})
    56. End Sub
    57. Public Sub RaisePropChanged(name As String, ParamArray names() As String)
    58. Dim names2(names.Length) As String
    59. names2(0) = name : Array.Copy(names, 0, names2, 1, names.Length)
    60. RaisePropChanged(names2.ToArray(Function(nm) New PropertyChangedEventArgs(nm)))
    61. End Sub
    62. Public Sub RaisePropChanged(ParamArray eventArgses() As PropertyChangedEventArgs)
    63. RaisePropChanged(DirectCast(eventArgses, IEnumerable(Of PropertyChangedEventArgs)))
    64. End Sub
    65. Public Sub RaisePropChanged(eventArgses As IEnumerable(Of PropertyChangedEventArgs))
    66. VerifyPropertyNames(eventArgses)
    67. For Each e In eventArgses
    68. OnPropertyChanged(e)
    69. Next
    70. End Sub
    71. Public Sub RaiseAllPropChanged()
    72. OnPropertyChanged(New PropertyChangedEventArgs(Nothing))
    73. End Sub
    74. Protected Overridable Sub OnPropertyChanged(e As PropertyChangedEventArgs)
    75. RaiseEvent PropertyChanged(Me, e)
    76. End Sub
    77. Private Shared _AllProperties As New Dictionary(Of Type, HashSet(Of String))
    78. <Conditional("DEBUG"), DebuggerStepThrough()> _
    79. Public Sub VerifyPropertyNames(eventArgses As IEnumerable(Of PropertyChangedEventArgs))
    80. Dim propNames As HashSet(Of String) = Nothing
    81. Dim tp = Me.GetType
    82. If Not _AllProperties.TryGetValue(tp, propNames) Then
    83. propNames = New HashSet(Of String)(From pd In Me.GetType.GetProperties Select pd.Name)
    84. propNames.Add("")
    85. _AllProperties.Add(tp, propNames)
    86. End If
    87. For Each pe In eventArgses
    88. If Not propNames.Contains(pe.PropertyName) Then Throw New Exception("trying to raise an unknown PropertyChanged")
    89. Next
    90. End Sub
    91. ''' <summary>Überschreibungen werden auch von ICloneable.Clone() aufgerufen</summary>
    92. Public Overridable Sub CopyTo(other As Object)
    93. End Sub
    94. Public Function Clone() As Object Implements ICloneable.Clone
    95. Dim cl = DirectCast(MemberwiseClone(), NotifyPropertyChanged)
    96. cl._PropertyChanged = Nothing
    97. CopyTo(cl)
    98. Return cl
    99. End Function
    100. End Class
    101. End Namespace


    File Counter:

    VB.NET-Quellcode

    1. Namespace System ' Vb-Workaround, um sowas wie das c# i++ - Feature zu haben
    2. Public Class Counter
    3. Public Value As Integer = 0
    4. <DebuggerStepThrough()> _
    5. Public Function Up(Optional ByVal stp As Integer = 1) As Integer ' incrementiert und returnt den vorherigen Wert
    6. Up = Value
    7. Value += stp
    8. End Function
    9. <DebuggerStepThrough()> _
    10. Public Function Down() As Integer
    11. Return Up(-1)
    12. End Function
    13. <DebuggerStepThrough()> _
    14. Public Shared Widening Operator CType(ByVal i As Integer) As Counter
    15. Return New Counter() With {.Value = i}
    16. End Operator
    17. <DebuggerStepThrough()> _
    18. Public Shared Widening Operator CType(ByVal i As Counter) As Integer
    19. Return i.Value
    20. End Operator
    21. <DebuggerStepThrough()> _
    22. Public Shared Operator &(ByVal left As String, ByVal right As Counter) As String
    23. Return right.Value.ToString
    24. End Operator
    25. <DebuggerStepThrough()> _
    26. Public Overrides Function ToString() As String
    27. Return Value.ToString()
    28. End Function
    29. End Class
    30. End Namespace
    Die tut bislang wie sie soll.
    Als besonderheit hat das Command auch eine Enabled- Property, wo man ihm zurnot ganz explizit sagen kann, ob es Enabled ist oder nicht.
    NotifyPropertyChanged ist meine Basisklasse für Viewmodelse

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades
    Danke für dein RelayCommand.
    Werde mir das nach C# übersetzten lassen und versuchen das einzusetzten und zu verstehen.
    Mit RelayCommand hab ich so meine Probleme. Ich brauch einen der Taskfähig ist, in dem Fall.

    @VaporiZed
    Schaumal ob du für diesen Code ein RelayCommand bauen kannst und ob
    der Button danch wieder Enabled wird.
    ViewModelBase:
    Spoiler anzeigen

    C#-Quellcode

    1. public class ViewModelBase : INotifyPropertyChanged
    2. {
    3. public event PropertyChangedEventHandler? PropertyChanged;
    4. private bool _isBusy;
    5. public bool IsBusy
    6. {
    7. get { return _isBusy; }
    8. set
    9. {
    10. if (_isBusy != value)
    11. {
    12. _isBusy = value;
    13. OnPropertyChanged(nameof(IsBusy));
    14. OnPropertyChanged(nameof(IsNotBusy));
    15. }
    16. }
    17. }
    18. public bool IsNotBusy
    19. {
    20. get { return !IsBusy; }
    21. }
    22. protected virtual void OnPropertyChanged(string propertyName)
    23. {
    24. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    25. }
    26. }

    MainViewModel:
    Spoiler anzeigen

    C#-Quellcode

    1. public class MainViewModel : ViewModelBase
    2. {
    3. public RelayCommand SimulateProcessCommand { get; }
    4. public MainViewModel()
    5. {
    6. SimulateProcessCommand = new RelayCommand(SimulateProcess, CanSimulateProcess);
    7. }
    8. private async Task SimulateProcess(object obj)
    9. {
    10. IsBusy = true;
    11. await Task.Delay(3000);
    12. IsBusy = false;
    13. }
    14. private bool CanSimulateProcess(object arg)
    15. {
    16. return IsNotBusy;
    17. }
    18. }


    MainWindow
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="IsBusyTestNetCore.MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:vm="clr-namespace:IsBusyTestNetCore.ViewModels"
    7. d:DataContext="{d:DesignInstance Type=vm:MainViewModel, IsDesignTimeCreatable=True}"
    8. xmlns:local="clr-namespace:IsBusyTestNetCore"
    9. xmlns:view="clr-namespace:IsBusyTestNetCore.Views"
    10. mc:Ignorable="d"
    11. Title="MainWindow" Height="450" Width="800">
    12. <Grid>
    13. <Grid.RowDefinitions>
    14. <RowDefinition/>
    15. <RowDefinition Height="100"/>
    16. </Grid.RowDefinitions>
    17. <view:IsBusyView Panel.ZIndex="99" Grid.RowSpan="2" />
    18. <StackPanel Background="WhiteSmoke" Grid.Row="1" Orientation="Horizontal" >
    19. <!--Simulate-Butto-->
    20. <Button Command="{Binding SimulateProcessCommand}"
    21. Content="Simuliere Process"
    22. Width="200"
    23. Height="50"
    24. Margin="10"/>
    25. <!--StackPanel Info-->
    26. <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
    27. <Label Content="IsBusy: "/>
    28. <TextBlock Text="{Binding IsBusy}" Foreground="Red" VerticalAlignment="Center"/>
    29. <Label Content="IsNotBusy: " Margin="20,0,0,0"/>
    30. <TextBlock Text="{Binding IsNotBusy}" Foreground="Blue" VerticalAlignment="Center"/>
    31. </StackPanel>
    32. </StackPanel>
    33. </Grid>
    34. </Window>


    IsBusyView
    Spoiler anzeigen

    C#-Quellcode

    1. <UserControl x:Class="IsBusyTestNetCore.Views.IsBusyView"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:IsBusyTestNetCore.Views"
    7. mc:Ignorable="d"
    8. d:DesignHeight="450" d:DesignWidth="800"
    9. Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}"
    10. Background="Transparent" >
    11. <Border Background="White" BorderBrush="Gainsboro"
    12. CornerRadius="10" Opacity="0.8" Width="450" Height="200">
    13. <Border.Effect>
    14. <DropShadowEffect BlurRadius="5" ShadowDepth="8" Opacity="0.5" />
    15. </Border.Effect>
    16. <StackPanel Margin="15" VerticalAlignment="Center">
    17. <TextBlock HorizontalAlignment="Center" Text="App is busy..." Margin="5" FontSize="16"/>
    18. <ProgressBar Background="White" IsIndeterminate="{Binding IsBusy}" Height="25" Margin="10" />
    19. </StackPanel>
    20. </Border>
    21. </UserControl>



    Hab mein RelayCommand jetzt erstmal weg gelassen.
    Versuchts mal mit eueren RelayCommands :)
    Execute muss Task (kein Sub/Void) sein, damit die Form nicht einfriert.
    Man soll ja für Execute-Methoden kein asyc void nehmen sondern asyc Task.
    async void würde zu nich erklärlichen verhalten führen bei Commands
    @ErfinderDesRades

    Hatte auch was ähnliches im ViewModel für die Execute Methode
    mit den CommandManager.

    C#-Quellcode

    1. private async Task SimulateProcess()
    2. {
    3. IsBusy = true;
    4. await Task.Delay(3000);
    5. IsBusy = false;
    6. System.Windows.Input.CommandManager.InvalidateRequerySuggested();
    7. }


    Das funktioniert zwar aber mich stört der System.Windows.Input namespace im ViewModel.
    Eigentlich auch im RelayCommand aber den Namespace braucht man eh für den ICommand.
    RelayCommand könnte man ja im Notfall auslagern ,in einem eignen Projekt, Core oder so.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Amro“ ()