דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
pcinfogmachP

pcinfogmach

@pcinfogmach
אודות
פוסטים
759
נושאים
192
שיתופים
0
קבוצות
0
עוקבים
3
עוקב אחרי
1

פוסטים

פוסטים אחרונים הגבוה ביותר שנוי במחלוקת

  • סקיצה איך ליישם Theming ב- wpf בצורה קלה ונוחה
    pcinfogmachP pcinfogmach

    @קומפיונט
    תודה על תגובה זו ועל שאר תגובותיך המועילות כל כך.
    אני מכיר את avalonia ואני ודה לך שהסבת את שתומת לבי שוב אל זה. אכן זה נראה אופציה טובה.
    תכלס, מכיוון שאני בעיקר מפתח תוספים לוורד אני תקוע עם wpf המקורי (ועם .net framework). או שאני טועה? (יש לי פרוייקטים אחרים גם אבל זה עיקר העיסוק שלי וממילא עיקר מוקד העניין שלי).

    סתם ככה היה לי הרגשה של "כמעט" כשהתעסקתי עם avalonia לא באתי ללכלך אבל מסקרן אותי כמה ההרגשה הזו אישית והאם יש בה ממש.

    אם כבר אנחנו מדברים על spinoff של wpf מה אתה אומר על uno? לא ניסיתי את זה מעניין לשמוע ממישהו שכן ניסה אם יש?

    לגופו של פוסט הסיבה שפיתחתי את החלון הנ"ל היה לצורך פיתוח UI שלא נמצא ב-avalonia ובשום מקום אחר. אז אמרתי לעצמי היי בוא נעשה מדריך יפה מזה.

    תכנות

  • סקיצה איך ליישם Theming ב- wpf בצורה קלה ונוחה
    pcinfogmachP pcinfogmach

    הרעיון שלי איך ליישם theming ב- wpf בצורה קלה


    שוב אני מוצא את עצמי מתמודד עם פתרונות מסורבלים. לכן יצרתי את הסקיצה הבאה עבור יישום themeing קליל פשוט ונוח (הצורך שלי היה מוגבל ל-Dark Mode, אבל ניתן להרחיב את הרעיון די בקלות).

    בבסיס האתגר הזה יש שני נושאים עיקריים:
    א. חלון WPF אינו מאפשר שינוי צבע ה-Title Bar.
    ב. יצירת Binding שיכול לשמש את כל התוכנה בצורה גלובלית.

    את עיצוב החלון כבר יצרתי בעבר, וכעת הפכתי אותו ל-Style. לדעתי, זו גישה הרבה יותר נוחה מאשר ליצור פקד חלון עם Theming, כיוון שהתעסקות עם ירושת פקד חלון ב-WPF היא קצת מורכבת. ישנם מדריכים רבים (עם הרבה באגים) בנושא, תכלס, חסכתי לכם הרבה עבודה אם זה מה שאתם מחפשים ה-style המצורף נקי ועובד חלק.

    כמה פרטים חשובים:
    ה-Style משתמש במחלקה סטטית שמארחת פקודות לסגירת חלון וכו', וגם מארחת ViewModel גלובלי. זהו פתרון קל ונוח לשימוש לצורך שינוי Theme.
    מכיוון שהצורך שלי היה ב-Dark Mode, יצרתי קוד שמזהה באופן אוטומטי אם המערכת מוגדרת ל-Dark Theme.
    בנוסף, הוספתי כפתור שמאפשר מעבר בין Dark Mode ל-Light Mode.
    עיצוב ה-Theme

    יצרתי מחלקה עם שני מאפיינים בסיסיים: Background ו-Foreground. לצרכים שלי זה היה מספיק, אבל אם אתם מחפשים משהו מורחב יותר, פשוט הוסיפו רכיבים למחלקה כיד ה' עליכם.
    Theme חדש ניתן להוסיף ל-Dictionary שנמצא ב-ViewModel, והיישום שלו אינטואיטיבי וקל.
    בנוסף, תוכלו לעשות Binding על ה-Dictionary ל-ListBox או ComboBox, ולאפשר למשתמש לבחור Theme בקלות.
    מכיוון שהמחלקה המארחת היא סטטית, תהיה לכם גישה נוחה ופשוטה ל-Themes מכל מקום בקוד.

    זהו פתרון יעיל ופשוט, ואני מאמין שיכול לחסוך לכם הרבה זמן ועבודה בהתמודדות עם אתגרי Theming ב-WPF.

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:mscorlib="clr-namespace:System;assembly=mscorlib"
                        xmlns:window="clr-namespace:MyWpf.Themes.Window;assembly=MyWpf"
                        xmlns:Converters="clr-namespace:MyWpf.Converters">
    
        <SolidColorBrush x:Key="HoverBackGroundBrush" Color="#ff646464" Opacity="0.2"/>
        <SolidColorBrush x:Key="SelectedBackGroundBrush" Color="#ff646464" Opacity="0.3"/>
        <SolidColorBrush x:Key="WindowBorderBrush" Color="#ff646464"/>
        <SolidColorBrush x:Key="TitlebarBrush" Color="#ff646464" Opacity="0.1"/>
        <mscorlib:Double x:Key="CaptionHieght">36</mscorlib:Double>
    
        <Style x:Key="TitleBarButton" TargetType="Button">
            <Setter Property="Width" Value="{Binding ActualHeight, RelativeSource={RelativeSource Mode=Self}}"/>
            <Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border" Background="{TemplateBinding Background}"
                            Padding="10">
                            <ContentPresenter x:Name="contentPresenter"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Background" Value="{StaticResource HoverBackGroundBrush}"/>
                            </Trigger>
                            <Trigger Property="AreAnyTouchesOver" Value="true">
                                <Setter Property="Background" Value="{StaticResource HoverBackGroundBrush}" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Background" Value="{StaticResource SelectedBackGroundBrush}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    
        <Style x:Key="TitleBarPathIcon" TargetType="Path">
            <Setter Property="Stroke" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Window}}"/>
            <Setter Property="StrokeThickness" Value="1"/>
            <Setter Property="Stretch" Value="Uniform"/>
        </Style>
    
        <Style x:Key="DarkModeIconPath" TargetType="Path">
            <Setter Property="Fill" Value="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Window}}"/>
            <Setter Property="Stretch" Value="Uniform"/>
        </Style>
    
        <Style x:Key="MaximizeRestorePath" TargetType="Path" BasedOn="{StaticResource TitleBarPathIcon}">
            <Style.Triggers>
                <!-- Trigger when Window is Maximized -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Maximized">
                    <Setter Property="Data" Value="M 13.5,12.5 H 20.5 V 19.5 H 13.5 Z M 15.5,12.5 V 10.5 H 22.5 V 17.5 H 20.5"/>
                </DataTrigger>
    
                <!-- Trigger when Window is Normal (Not Maximized) -->
                <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}"   Value="Normal">
                    <Setter Property="Data" Value="M 13.5,10.5 H 22.5 V 19.5 H 13.5 Z"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    
        <Style TargetType="Window" x:Key="ThemedWindow">
            <Setter Property="WindowChrome.WindowChrome">
                <Setter.Value>
                    <WindowChrome
                    CornerRadius="{x:Static SystemParameters.WindowCornerRadius}"
                    UseAeroCaptionButtons="False"
                    CaptionHeight="{StaticResource CaptionHieght}"/>
                </Setter.Value>
            </Setter>
    
            <!--<Setter Property="FlowDirection" Value="{Binding Path=(window:ThemeHelper.FlowDirection)}" />-->
            <Setter Property="Background" Value="{Binding Source={x:Static window:ThemeHelper.ThemeModel}, Path=CurrentTheme.Background}"/>
            <Setter Property="Foreground" Value="{Binding Source={x:Static window:ThemeHelper.ThemeModel}, Path=CurrentTheme.Foreground}"/>
    
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Window">
                        <Border  BorderBrush="{StaticResource WindowBorderBrush}" 
                                 BorderThickness="0.8"
                                 Background="{TemplateBinding Background}">
                            <Grid x:Name="RootGrid">
                                <Grid.RowDefinitions>
                                    <RowDefinition x:Name="TitleBarRow" Height="auto"/>
                                    <RowDefinition x:Name="ContentRow" Height="*"/>
                                </Grid.RowDefinitions>
    
                                <Grid x:Name="TitleBarGrid"
                                      Height="{StaticResource CaptionHieght}"
                                      Background="{StaticResource TitlebarBrush}">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="auto" x:Name="CaptionColumn"/>
                                        <ColumnDefinition Width="*" x:Name="PlaceHolderColumn"/>
                                        <ColumnDefinition Width="auto" x:Name="TitleBarButtonsColumn"/>
                                    </Grid.ColumnDefinitions>
    
                                    <TextBlock x:Name="WindowTitle" Padding="10" VerticalAlignment="Center" IsHitTestVisible="False"
                                               Text="{TemplateBinding Title}"/>
    
                                    <StackPanel x:Name="TitleBarButtonsPanel" Orientation="Horizontal" Grid.Column="2" Margin="1">
                                        <Button Style="{StaticResource TitleBarButton}"
                                                Command="{Binding Source={x:Static window:ThemeHelper.ThemeModel}, Path=ToggleThemeCommand}"
                                                CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
                                            <Path Style="{StaticResource DarkModeIconPath}"
                                                  Data="M7.5,2C5.71,3.15 4.5,5.18 4.5,7.5C4.5,9.82 5.71,11.85 7.53,13C4.46,13 2,10.54 2,7.5A5.5,5.5 0 0,1 7.5,2M19.07,3.5L20.5,4.93L4.93,20.5L3.5,19.07L19.07,3.5M12.89,5.93L11.41,5L9.97,6L10.39,4.3L9,3.24L10.75,3.12L11.33,1.47L12,3.1L13.73,3.13L12.38,4.26L12.89,5.93M9.59,9.54L8.43,8.81L7.31,9.59L7.65,8.27L6.56,7.44L7.92,7.35L8.37,6.06L8.88,7.33L10.24,7.36L9.19,8.23L9.59,9.54M19,13.5A5.5,5.5 0 0,1 13.5,19C12.28,19 11.15,18.6 10.24,17.93L17.93,10.24C18.6,11.15 19,12.28 19,13.5M14.6,20.08L17.37,18.93L17.13,22.28L14.6,20.08M18.93,17.38L20.08,14.61L22.28,17.15L18.93,17.38M20.08,12.42L18.94,9.64L22.28,9.88L20.08,12.42M9.63,18.93L12.4,20.08L9.87,22.27L9.63,18.93Z"/>
                                        </Button>
    
                                        <Button Style="{StaticResource TitleBarButton}"
                                             Command="{Binding Source={x:Static window:ThemeHelper.MinimizeCommand}}"
                                             CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
                                            <Path Style="{StaticResource TitleBarPathIcon}" Data="M 13,15 H 23"/>
                                        </Button>
    
                                        <Button Style="{StaticResource TitleBarButton}"
                                             Command="{Binding Source={x:Static window:ThemeHelper.MaximizeRestoreCommand}}"
                                             CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
                                            <Path Style="{StaticResource MaximizeRestorePath}"/>
                                        </Button>
    
                                        <Button Style="{StaticResource TitleBarButton}"
                                              Command="{Binding Source={x:Static window:ThemeHelper.CloseWindowCommand}}"
                                              CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
                                            <Path Style="{StaticResource TitleBarPathIcon}" Data="M 13,11 22,20 M 13,20 22,11"/>
                                        </Button>
    
                                    </StackPanel>
                                </Grid>
    
                                <ContentPresenter x:Name="PART_MainContentPresenter"  Grid.Row="1"/>
                            </Grid>
                        </Border>
    
                        <ControlTemplate.Triggers>
                            <Trigger Property="WindowState" Value="Maximized">
                                <Setter TargetName="RootGrid" Property="Margin" Value="7.5"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    
    using MyWpf.Models;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace MyWpf.Themes.Window
    {
        public static class ThemeHelper
        {
            private static ThemeModel _themeModel;
            public static ThemeModel ThemeModel
            {  
                get { if (_themeModel == null)
                        _themeModel = new ThemeModel();
                    return _themeModel; } 
            }
    
            //public static double CaptionHeight { get => SystemParameters.WindowCaptionHeight + 10;} 
            //public static FlowDirection FlowDirection { get => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "he" ? FlowDirection.RightToLeft : FlowDirection.LeftToRight; } 
    
            public static ICommand CloseWindowCommand = new RelayCommand<System.Windows.Window>((window) => window.Close(), (window) => window != null);
            public static ICommand MaximizeRestoreCommand = new RelayCommand<System.Windows.Window>((window) => window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized, (window) => window != null);
            public static ICommand MinimizeCommand = new RelayCommand<System.Windows.Window>((window) => window.WindowState = WindowState.Minimized, (window) => window != null);
        }
    
        public class ThemeModel : ViewModelBase
        {
            private bool _isDarkTheme;
            private ThemeObject _currentTheme;
    
            public Dictionary<string, ThemeObject> ThemeCollection = new Dictionary<string, ThemeObject>
            {
                { "DarkTheme", new ThemeObject{ Background = new SolidColorBrush(Color.FromRgb(34, 34, 34)),
                                                Foreground = new SolidColorBrush(Color.FromRgb(200, 200, 200))} },
                { "LightTheme", new ThemeObject{ Background = new SolidColorBrush(Colors.White),
                                 Foreground = new SolidColorBrush(Colors.Black)} },
            };
    
            public ThemeObject CurrentTheme { get => _currentTheme; set => SetProperty(ref _currentTheme, value); }
    
            public ICommand ToggleThemeCommand => new RelayCommand<System.Windows.Window>(ToggleTheme, (window) => window != null);
    
            public ThemeModel() 
            {
                _isDarkTheme = GetSystemTheme;
                _currentTheme = _isDarkTheme ? ThemeCollection["DarkTheme"] : ThemeCollection["LightTheme"];
            }
    
            public void ToggleTheme(System.Windows.Window window)
            {
                CurrentTheme = _isDarkTheme ? ThemeCollection["LightTheme"] : ThemeCollection["DarkTheme"];
                _isDarkTheme = !_isDarkTheme;
            }
    
            static bool GetSystemTheme
            {
                get
                {
                    string registryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
                    string registryValueName = "AppsUseLightTheme";
    
                    try
                    {
                        using (var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(registryKeyPath))
                            if (key?.GetValue(registryValueName) is int value)
                                return value == 0; // 0 means Dark Theme is enabled, 1 means Light Theme
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }
                    return false;
                }
            }
    
            public class ThemeObject
            {
                public SolidColorBrush Background { get; set; }
                public SolidColorBrush Foreground { get; set; }
            }
    
        }
    }
    

    הקוד משתמש בשני מחלקות שימושיות המהוות בסיס טוב עבור כל viewmodel

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    namespace MyWpf.Models
    {
        public class ViewModelBase : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
            {
                if (EqualityComparer<T>.Default.Equals(field, value)) return false;
                field = value;
                OnPropertyChanged(propertyName);
                return true;
            }
        }
    
    }
    
    using System;
    using System.Windows.Input;
    
    namespace MyWpf.Models
    {
        public class RelayCommand : ICommand
        {
            private readonly Action _execute;
            private readonly Func<bool> _canExecute;
    
            public RelayCommand(Action execute, Func<bool> canExecute = null)
            {
                _execute = execute ?? throw new ArgumentNullException(nameof(execute));
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
            public void Execute(object parameter) => _execute();
    
            public event EventHandler CanExecuteChanged
            {
                add => CommandManager.RequerySuggested += value;
                remove => CommandManager.RequerySuggested -= value;
            }
        }
    
        public class RelayCommand<T> : ICommand
        {
            private readonly Action<T> _execute;
            private readonly Func<T, bool> _canExecute;
    
            public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
            {
                _execute = execute ?? throw new ArgumentNullException(nameof(execute));
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter) => _canExecute?.Invoke((T)parameter) ?? true;
    
            public void Execute(object parameter) => _execute((T)parameter);
    
            public event EventHandler CanExecuteChanged
            {
                add => CommandManager.RequerySuggested += value;
                remove => CommandManager.RequerySuggested -= value;
            }
        }
    }
    
    תכנות

  • Wpf: איך ליישם dataconext עבור style בתוך resource dictionary ??
    pcinfogmachP pcinfogmach

    @dovid
    נגיד אני רוצה מבנה נתונים של תיקייות ומסמכים ב-treeview ואני בונה לזה מודל ו style יפה שאמור לשמש אותי בכמה תוכנות
    לצרף גם קוד דוגמא?

    תכנות

  • Wpf: איך ליישם dataconext עבור style בתוך resource dictionary ??
    pcinfogmachP pcinfogmach

    לאחרונה חקרתי רבות את איך לשפר את השימושיות (Reusability) והניידות (Portability) בקודים שלי. מחקר זה הוביל אותי להעדיף שימוש מוגבר ב-ResourceDictionary במקום עיצובים ישירים בתוך הפקדים עצמם מה שהופך את הקוד שלי ליותר מודולרי וניתן לשימוש חוזר.
    כתוצאה מכך, אני מעדיף גם שה-Binding עבור פקדים מסוימים יוגדר מראש בתוך ה-ResourceDictionary.

    תכלס אפשר לעשות binding בתוך ResourceDictionary על ידי שימוש במחלקה סטטית אבל גישה זו מאוד מגובלת כי בסוף היום זה ניהול סטטי של פקדים ולא דינאמי כמו שאמור להיות.

    שוין כנראה זה לא הכיוון תכלס אפשר לבנות פקדים ב-wpf ואז ה-binding שלהם זמין אבל יש לזה מחיר מסויים. מצד maintanenace זה לא כמו השגר ושלח של style שמחובר ל-viemodel.

    תכנות

  • Wpf: איך ליישם dataconext עבור style בתוך resource dictionary ??
    pcinfogmachP pcinfogmach

    מישהו יודע איך ליישם dataconext עבור style בתוך resource dictionary
    הדרך הרגילה לא עובד לי

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:mscorlib="clr-namespace:System;assembly=mscorlib"
                        xmlns:window="clr-namespace:MyWpf.Themes.Window;assembly=MyWpf"
                        xmlns:Converters="clr-namespace:MyWpf.Converters">
    
        <Style TargetType="Window" x:Key="ThemedWindow">
            <Setter Property="DataContext">
                <Setter.Value>
                    <window:WindowThemingHelper
             </Setter.Value>
            </Setter>
    
    תכנות

  • Debugging על ViewModel ב-WPF
    pcinfogmachP pcinfogmach

    @קומפיונט
    תודה
    אני מודע לזה שאפשר לזהות את הבעיה ככה
    זה מתסכל אותי אבל שאני לא יכול לדבג בצורה ישירה כמו בקוד רגיל של C#

    תכנות

  • שימוש נכון ב-await Task.Run ב-C#
    pcinfogmachP pcinfogmach

    אשמח אם מישהו יסביר לי קצת יותר מתי ואיך נכון להשתמש ב-await Task.Run.
    כמו"כ קראתי כמה פעמים על משהו שנקרא תנאי תחרות (Race Condition) כשמשתמשים ב-Multithreading - אני חייב לומר שלא בדיוק הבנתי את הנושא.
    לעת עתה כל מה שאני יודע שזה נותן לי אפשרות הריץ קוד בלי לחסום את ה-UI. או להריץ כמה דברים בו זמנית (שזה בעצם אותו עיקרון).

    שאלותיי הם:
    מהם ההדרכות לכתיבת קוד אסינכרוני ב-C# וממה יש להיזהר?

    דוגמת קוד:
    האם קוד זה טוב או בעייתי או טעון שיפור? אשמח גם לקבל הסבר מדוע:

    async Task LoadCommentries(IOrderedEnumerable<LinkItem> commentryList, int lineIndex)
    {
        Commentry = await Task.Run(async () =>
        {
            var stringBuilder = new StringBuilder();
            foreach (var commentry in commentryList)
            {
                stringBuilder.AppendLine(await GetCommentryLine(commentry.path_2, lineIndex));
            }
            return stringBuilder.ToString();
        });
    }
    
    async Task<string> GetCommentryLine(string path, int lineIndex)
    {
        using (var reader = new StreamReader(path))
        {
            int currentIndex = 0;
            while (!reader.EndOfStream && currentIndex < lineIndex)
            {
                await reader.ReadLineAsync();
                currentIndex++;
            }
            return await reader.ReadLineAsync();
        }
    }
    
    תכנות

  • Debugging על ViewModel ב-WPF
    pcinfogmachP pcinfogmach

    @Mordechai-0
    שוב נתקלתי בבעיה זו והעצה שלך לא עזרה...
    😞

    תכנות

  • מבנה נתונים גלובלי עבור Checked TreeView ב-Wpf
    pcinfogmachP pcinfogmach

    7565919b-5ed3-46b3-a7ae-98317cc9b0df-image.png

    כידוע, הדרך הטובה ביותר להתנהל עם TreeView ב-WPF היא עם מבנה נתונים הררכי, ו-HierarchicalDataTemplate ב-WPF נבנה במיוחד למטרה זו.
    אחרי שמצאתי את עצמי בפעם השלישית בונה מבנה נתונים עבור Checked TreeView (ראה תמונה), החלטתי לשבת כמה דקות ולבנות משהו יותר גלובלי שיאפשר לי להשתמש בו גם בעתיד. הרעיון הוא לייצר מחלקה בסיסית המכילה את כל מה שדרוש עבור מטרה זו, כך שאוכל לרשת אותה ולהשתמש בה עבור כל מבנה נתונים הררכי באופן כללי עם הדרישה הזו של Checked TreeView.

    שימו לב! אני הגדרתי את ה-Default של ה-IsChecked כ-false ייתכן ותרצו לשנות את זה ל-true תלוי באמפלמנטציה שלכם.

    אם לא הבנתם את הנושא דיו והוא מעניין אתכם? אנא קיראו כתבה זו כהקדמה:
    https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode

    להלן הקוד:

    ///sample usage
    //public class MyCheckedItem : TreeItemBase<MyCheckedItem>
    //{
    //    // Custom properties if needed
    //}
    
    using System.Collections.Generic;
    using System.Linq;
    
    namespace WpfLib.ViewModels
    {
        public class CheckedTreeItemBase<T> : TreeItemBase<T> where T : CheckedTreeItemBase<T>
        {
            bool? _isChecked = false;
            public bool? IsChecked { get => _isChecked; set => SetCheckedValue(value, true); }
    
            public void SetCheckedValue(bool? isChecked, bool updateChildren)
            {
                if (SetProperty(ref _isChecked, isChecked, nameof(IsChecked)))
                {
                    if (updateChildren && Items != null)
                    {
                        foreach (var child in Items)
                        {
                            if (child.IsChecked != isChecked)
                                child.IsChecked = isChecked == true;
                        }
                    }
    
                    if (Parent != null)
                    {
                        var siblings = Parent.Items;
                        var parentCheckedValue = siblings.All(c => c.IsChecked == true) ? true :
                                                 siblings.All(c => c.IsChecked == false) ? (bool?)false : null;
                        Parent.SetCheckedValue(parentCheckedValue, false);
                    }
                }
            }
    
            public IEnumerable<T> EnumerateCheckedItems()
            {
                if (Items != null)
                {
                    foreach (var child in Items)
                    {
                        if (child.IsChecked == true)
                            yield return child;
    
                        foreach (var item in child.EnumerateCheckedItems())
                            yield return item;
                    }
                }
            }
        }
    }
    

    המודל יורש ממודל treeitembase שמשמש כבסיס לכל מודל היררכי בעץ נתונים

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text.Json.Serialization;
    
    namespace WpfLib.ViewModels
    {
        public class TreeItemBase<T> : ViewModelBase where T : TreeItemBase<T>
        {
            string _name;
            ObservableCollection<T> _items = new ObservableCollection<T>();
    
            [JsonIgnore] public T Parent { get; set; }
            public virtual string Name { get => _name; set => SetProperty(ref _name, value); }
            public ObservableCollection<T> Items { get => _items; set => SetProperty(ref _items, value); }
    
            public override string ToString() => Name;
    
            public void AddChild(T item)
            {
                if (Items == null)
                    Items = new ObservableCollection<T>();
                Items.Add(item);
                item.Parent = (T)this;
            }
    
            public IEnumerable<T> EnumerateItems()
            {
                if (_items == null) yield break;
    
                foreach (var item in _items)
                {
                    yield return item;
                    foreach (var child in item.EnumerateItems())
                        yield return child;
                }
            }
        }
    
    }
    
    

    המודל יורש מודל אחר שימושי בשם ViewModelBase המהווה בסיס טוב עבור כל viewModle ב-Wpf

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    namespace MyModels
    {
        public class ViewModelBase : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
            {
                if (EqualityComparer<T>.Default.Equals(field, value)) return false;
                field = value;
                OnPropertyChanged(propertyName);
                return true;
            }
        }
    
    }
    
    
    תכנות

  • עזרה בביטוי רגולארי
    pcinfogmachP pcinfogmach

    לגופו של עניין:
    אין לי היכרות עם מדיה-ויקי או עם הפורמט שלו, והמשמעות של הנקודה ושל ה-"|" אינן ברורות לי דיו. עם זאת, אני מניח שמדובר בפורמט מסודר עם כללים, ואם תלמד איך הוא בנוי, אני בטוח שתוכל לנתח כל טקסט בסגנון הזה די בקלות הכל שאלה של כמה זמן אתה מוכן להשקיע.

    אם נתעלם לרגע מהנקודה ומה-"|", נוכל להשתמש בשילוב של רג'קס וקוד רקורסיבי עם מבנה נתונים פשוט (@dovid רמז לזה כבר).
    אבל חשוב לציין שזה בהנחה שהטקסט לא מכיל שגיאות או אי-עקביות – אחרת זה כאב ראש * 20.
    להלן דוגמא ב-C# שהזנתי ל-LinqPad, הקוד הינו סקיצה בעלמא תוכל לשפר אותו כיד ה' הטובה עליך:

    void Main()
    {
        string content = "{{some content{{some more content{{some more content{{some more content}}}}}}}}";
            var root = new NestedContent(content, null);
            root.Dump(); // Dump the root object to view its structure
    }
    
    class NestedContent
    {
        public string Content { get; set; }
        public NestedContent Child { get; set; }
    
        public NestedContent(string content, NestedContent parent)
        {
            // Trim only the outermost braces (single pair at start and end)
            if (content.StartsWith("{{") && content.EndsWith("}}"))
            {
                content = content.Substring(2, content.Length - 4);
            }
    
            var match = Regex.Match(content, @"\{\{.*\}\}");
            if (match.Success)
            {
                string nestedContent = match.Value;
                this.Content = content.Replace(nestedContent, ""); // Replace inner braces content
                Child = new NestedContent(nestedContent, this); // Recursive call for nested content
            }
            else
            {
                this.Content = content; // Set content when no more nested structures
            }
        }
    }
    
    

    והתוצאה:

    d7b843dd-ffba-4875-bdb5-2e95805263aa-image.png

    תכנות

  • עזרה בביטוי רגולארי
    pcinfogmachP pcinfogmach

    @האדם-החושב
    זה יפה שכולם פיענחו מה אתה רוצה לי זה לקח קצת זמן עד שקלטתי שאני צריך לקרוא את מה שכתבת בפנים בקונטקסט של הכותרת ולנחש שבעצם אתה שואל איך לעשות רגקס שיפתור את הבעיה.
    אתה כותב הבעיה מתחילה מבלי לפרט מה עשית לפני שהבעיה התחילה.

    אישית לא הייתי שואל ככה אלא איך לפתור את הבעיה והאם רגקס הוא כיוון טוב.

    תכנות

  • Debugging על ViewModel ב-WPF
    pcinfogmachP pcinfogmach

    @yossiz כתב בDebugging על ViewModel ב-WPF:

    אגב, אני לא מפתח WPF אבל יצרתי פרוייקט דמו כדי לבדוק את הנושא
    הוספתי לפרוייקט שלי UserControl ובתוך הconstructor זרקתי שגיאה

    אכן במקרה כזה אין לי בעיות הבעיות מתחילות כאשר אני משתמש במבנה MVVM ויש בעיה במודל או ב-ViewModel (שם עיקר הכוח של wpf בא לידי ביטוי). נכון אפשר להסתכל על פרטי השגיאה אבל זה די מתסכל לא להגיע ישר לבעיה ולתקן כמו שאני רגיל.
    מה שכתבת בהחלט עזר לי להבין יותר. התיעוד בכל הנושא הזה מאוד לא ברור לי. ובפרט מה בדיוק עושה מה ש@Mordechai-0 אמר Enable Just my code. הנסיון שלי הוא ש-visual studio הוא תוכנה מורכבת וכשמתחילים לשנות את ההגדרות אם לא באמת מבינים מה עושים אזי עדיף לא לשנות.

    תכנות

  • Debugging על ViewModel ב-WPF
    pcinfogmachP pcinfogmach

    @Mordechai-0
    אתה יכול להרחיב קצת על מה האפשרות הזו עושה (ובפרט למה זה לא ה-default?)
    תודה

    תכנות

  • Debugging על ViewModel ב-WPF
    pcinfogmachP pcinfogmach

    כאשר יש בעיה ב-ViewModel אצלי במקום לעצור על נקודת הבעיה כמו שקורה כרגיל ב-C# הוא עוצר על נקודה זו (שבתמונה דלהלן) יש למישהו עצה?

    6f887d7e-8fbb-4c77-84b2-c4d2c5a36fd5-image.png

    תכנות

  • API לקבלת רשימת דפים וסימנים בספרי היסוד התורניים
    pcinfogmachP pcinfogmach

    @NH-LOCAL
    כדי להתגבר על חוסר העקביות ברמות הכותרות, אפשר להשתמש במבנה היררכי, כמו Stack, כדי לעקוב אחר ה-parent האחרון. כך ניתן לתקן את רמת הכותרת בהתאם להקשר ולהבטיח זיהוי נכון של המספרים והכותרות.

    תכנות

  • TextBoxFocusBehavior - לשיפור חוויית המשתמש ב-WPF
    pcinfogmachP pcinfogmach

    @ivrtikshoret
    תודה שעלית את השאלה הזו
    אני מאד אוהב לשתף ולעזור אך תהיתי לעצמי לא פעם אם יש בזה תועלת למישהו
    היה חסר לי confirmation תודה.
    חוץ מזה אני מאוד נבניתי מהפורום כאן הערה פה הערה שם של אנשים טובים על הקודים שלי נתנו לי המון ידע.

    תכנות

  • TextBoxFocusBehavior - לשיפור חוויית המשתמש ב-WPF
    pcinfogmachP pcinfogmach

    כאשר עובדים עם TextBox ב-WPF, לפעמים נרצה לשפר את חוויית המשתמש על ידי ביצוע פעולות אוטומטיות, כמו בחירת כל הטקסט כאשר הרכיב מקבל פוקוס או קביעה אוטומטית של פוקוס על TextBox בעת הטעינה.

    אשמח לקבל הערות והארות.

    מצו"ב הקוד:

    public class TextBoxFocusBehavior
    {
        public static bool GetSelectAll(FrameworkElement frameworkElement)
        {
            return (bool)frameworkElement.GetValue(SelectAllProperty);
        }
    
        public static void SetSelectAll(FrameworkElement frameworkElement, bool value)
        {
            frameworkElement.SetValue(SelectAllProperty, value);
        }
    
        public static bool GetCaptureFocus(FrameworkElement frameworkElement)
        {
            return (bool)frameworkElement.GetValue(CaptureFocusProperty);
        }
    
        public static void SetCaptureFocus(FrameworkElement frameworkElement, bool value)
        {
            frameworkElement.SetValue(CaptureFocusProperty, value);
        }
    
        public static readonly DependencyProperty CaptureFocusProperty =
            DependencyProperty.RegisterAttached("CaptureFocus",
                typeof(bool), typeof(TextBoxFocusBehavior),
                new FrameworkPropertyMetadata(false, OnCaptureFocusChanged));
    
        public static readonly DependencyProperty SelectAllProperty =
                 DependencyProperty.RegisterAttached("SelectAll",
                    typeof(bool), typeof(TextBoxFocusBehavior),
                    new FrameworkPropertyMetadata(false, OnSelectAllChanged));
    
        private static void OnSelectAllChanged
                   (DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var frameworkElement = d as FrameworkElement;
            if (frameworkElement == null) return;
    
            if (e.NewValue is bool == false) return;
    
            if ((bool)e.NewValue)
            {
                frameworkElement.GotFocus += SelectAll;
                frameworkElement.PreviewMouseDown += IgnoreMouseButton;
            }
            else
            {
                frameworkElement.GotFocus -= SelectAll;
                frameworkElement.PreviewMouseDown -= IgnoreMouseButton;
            }
        }
    
        private static void OnCaptureFocusChanged
                  (DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var frameworkElement = d as FrameworkElement;
            if (frameworkElement == null) return;
    
            if (e.NewValue is bool == false) return;
    
            if ((bool)e.NewValue)
            {
                frameworkElement.Loaded += FrameworkElement_Loaded;
            }
            else
            {
                frameworkElement.Loaded -= FrameworkElement_Loaded;
            }
        }
    
        private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e)
        {
            var frameworkElement = e.OriginalSource as FrameworkElement;
            frameworkElement.Focus();
        }
    
        private static void SelectAll(object sender, RoutedEventArgs e)
        {
            var frameworkElement = e.OriginalSource as FrameworkElement;
            if (frameworkElement is TextBox)
                ((TextBoxBase)frameworkElement).SelectAll();
            else if (frameworkElement is PasswordBox)
                ((PasswordBox)frameworkElement).SelectAll();
        }
    
        private static void IgnoreMouseButton
                (object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var frameworkElement = sender as FrameworkElement;
            if (frameworkElement == null || frameworkElement.IsKeyboardFocusWithin) return;
            e.Handled = true;
            frameworkElement.Focus();
        }
    }
    

    המחלקה TextBoxFocusBehavior מספקת שתי יכולות:

    Select All: בחירת כל הטקסט כאשר הרכיב מקבל פוקוס.
    Capture Focus: קביעה כי רכיב מסוים יקבל פוקוס אוטומטית בעת טעינת החלון.
    

    דוגמאות שימוש:

    <TextBox Text="Hello, World!" 
             local:TextBoxFocusBehavior.SelectAll="True" 
             local:TextBoxFocusBehavior.CaptureFocus="True" />
    
    תכנות

  • מדריך: איך לייצר לוקליזציה ב-wpf בצורה פשוטה וקלילה
    pcinfogmachP pcinfogmach

    @OdedDvir
    json הוא פורמט עבודה נוח וגמיש יותר בשבילי, את שאר הנימוקים כבר כתבתי וכתבו אחרים למעלה. כל אחד לפי טעמו כמובן. אני לא יכול להכחיש שיש איזושהי מעלה בפיתרון המובנה אישית זה היה מריטת עצבים עד שנמאס לי והלכתי על כיוון אחר. כשאתה בונה כמה פרוייקטים במקביל הפעולות המכניות הזוטרות האלה שחוזרים על עצמם שוב ושוב מתחילים להציק לך מאוד הם מפריעם לזרימה ולכיף שבתכנות. אז בחרתי בדרך קצת פחות מציקה.
    נקוט האי כללא בידך (בעירבון מוגבל): כל דבר שאפשר לעשות עליו העתק הדבק ולמחזר אותו עבור הפרוייקט הבא שלך שווה זהב. תרגומים של פקדים שהרבה פעמים חוזרים על עצמם שווים זהב ב-json.

    תכנות

  • התייעצות בתכנון מסד נתונים עבור מאגר תורני
    pcinfogmachP pcinfogmach

    @yossiz
    אוקיי הבנתי הטענה היא שמספיק למפות את הקובץ לא צריך לשמור אותו כלל במסד - יפה!
    כמובן שיש משהו שמרוויחים חינם במסד והוא היכולת חיפוש בתוכן.

    תכנות
  • 1
  • 2
  • 11
  • 12
  • 13
  • 14
  • 15
  • 37
  • 38
  • 13 / 38
  • התחברות

  • אין לך חשבון עדיין? הרשמה

  • התחברו או הירשמו כדי לחפש.
  • פוסט ראשון
    פוסט אחרון
0
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום