Ответы пользователя по тегу C#
  • Как улучшить код?

    gdt
    @gdt
    Программист
    Попробуйте метод Array.IndexOf:
    var pattern = Num1.ToString();
    var index = Array.IndexOf(textBox2.Lines, pattern);
    label2.Text = index.ToString();
    Ответ написан
  • Как менять цвет при наведении на контрол?

    gdt
    @gdt
    Программист
    Вот так работает:
    <ControlTemplate x:Key="TestButtonTemplate" TargetType="Button">
        <Border Background="{TemplateBinding Background}"
                BorderThickness="0"
                CornerRadius="5"
                Height="{TemplateBinding Height}"
                Width="{TemplateBinding Width}">
            <ContentControl Foreground="{TemplateBinding Foreground}"
                            Content="{TemplateBinding Content}"
                            VerticalAlignment="Center"
                            HorizontalAlignment="Center"
                            FontSize="{TemplateBinding FontSize}"
                            FontFamily="{TemplateBinding FontFamily}"/>
        </Border>
    
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Background" Value="Red" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>


    Лениво разбираться в причинах, но наверное вам нужно менять свойства самого контрола, раз вы на них биндитесь в Border
    Ответ написан
    Комментировать
  • Как мгновенно завершить Task?

    gdt
    @gdt
    Программист
    Извините, что не отвечаю на ваш вопрос - а почему не используете https://github.com/XamlAnimatedGif/XamlAnimatedGif ?

    По делу - если мне не изменяет память, нет простого способа прибить Task, для этого нужно использовать CancellationTokenSource, что вы и делаете в приведенном примере. Если отмена через CancellationTokenSource не срабатывает по какой-то причине - поставьте брейкпоинты или навтыкайте логов через каждую строку, найдите проблемное место, и уже исходя из этой информации решайте.
    Исходя из вашей проблемы, для начала после отмены можно просто подождать завершения таска:
    // Метод в котором останавливаете анимацию
    cancellationTokenSource3.Cancel();
    await th_Image3;

    или
    // Метод в котором останавливаете анимацию
    cancellationTokenSource3.Cancel();
    th_Image3.GetAwaiter().GetResult();

    Так вы по-крайней мере должны избавиться от наложения тасков друг на друга.

    Далее, таски можно чуть-чуть проще запускать, вот так:
    th_Image3 = Task.Run(() => 
    { 
        // ......
    });


    Кроме того, если вам действительно нужно, чтобы код внутри Task.Run всегда выполнялся только в единственном экземпляре - это значит, что вам нужна критическая секция. В данном случае можно сделать при помощи семафоров:
    // ......................
    Semaphore _semaphore = new Semaphore(1, 1);
    // ......................
    th_Image3 = Task.Run(() =>
    {
        _semaphore.WaitOne();
    
        try
        {
            // Показ GIF
        }
        finally
        {
            _semaphore.Release();
        }
    });


    Или же можно использовать метод ContinueWith, чтобы организовать какое-то подобие очереди задач:
    // .................................................
    Task th_Image3 = Task.FromResult(0);
    // .................................................
    th_Image3 = th_Image3.ContinueWith(() => 
    {
        // Отображение GIF
    });


    В общем много чего можно сделать, проще всего не изобретать велосипед и взять готовое решение.
    Ответ написан
  • Как изменить значение чексбокса из другого окна?

    gdt
    @gdt
    Программист
    Как всегда, тут есть простой и правильный способ решения проблемы
    Простой метод - просто вызвать метод этого окна. Вы же где-то его отображаете, так ведь? Заведите поле с типом вашего окна с методом, там, где показываете окно - сохраните его туда. Меняете чекбокс - обращаетесь к полю, вызываете метод. Примерно так (код не запускал, где-то может быть нужно немножко иначе написать):
    public class MainWindow : Window
    {
        private WindowWithMetod _windowWithMetod;
        
        // ........................................................................................
    
        private void DisplaySecondWindow()
        {
            _windowWithMethod = new WindowWithMethod;
            _windowWithMethod.Closed += (s, e) => _windowWithMethod = null;
            _windowWithMethod.Show();
        }
    
        private void HandleCheckboxValueChanged(object sender, EventArgs args)
        {
            _windowWithMethod?.Method();
        }
    }


    Правильный метод - подумать, перед тем, как что-то писать. Смотрите, у вас есть какое-то состояние чего-то, выражаемое чекбоксом, это значит, что имеет смысл держать это что-то отдельно от обоих форм. Нам нужно:
    1. Задавать и хранить какое-то булево значение
    2. Иметь возможность реагировать на его изменение


    Определим интерфейсы, с которыми нам было бы удобно иметь дело (имена лучше дать более осмысленные):
    public interface IBooleanState
    {
        public bool State { get; set; }
    }


    public interface IBooleanStateEvents
    {
        public event EventArgs<bool> StateChanged;
    }


    Если у вас нет generic-версии EventArgs, возьмите эту:
    public sealed class EventArgs<T> : EventArgs
    {
        public EventArgs(T value)
        {
            Value = value;
        }
    
        public T Value { get; }
    }


    Далее, реализуем наши интерфейсы, удобнее будет сделать это в одном классе:
    public sealed class BooleanState : IBooleanState, IBooleanStateEvents
    {
        private bool _state;
    
        public event EventArgs<bool> StateChanged;
    
        public bool State
        {
            get => _state;
            set
            {
                if (value == _state)
                {
                    return;
                }
                
                _state = value;
    
               StateChanged?.Invoke(this, new EventArgs(value));
            }
        }
    }


    Далее, нам нужно как-то получить доступ ко всему этому добру из наших форм. Меняем конструкторы и добавляем поля:
    public class MainWindow : Window
    {
        private readonly IBooleanState _state;
        // ..................
        public MainWindow(IBooleanState state)
        {
            _state = state;
        }
    }

    public class WindowWithMethod : Window
    {
        private readonly _stateEvents;
    
        public WindowWithMethod(IBooleanStateEvents stateEvents)
        {
            _stateEvents = stateEvents;
        }
    }

    Когда создаём окна, передаём туда экземпляр нашего BooleanState:
    // Наверное где-то в Program.cs 
    private readonly BooleanState _state = new BooleanState();
    //................................................
    Application.Run(new MainWindow(_state));
    //................................................

    Для второго окна всё зависит от того, где вы его создаёте, если тоже из Program то и передаёте так же, если из MainWindow - придётся кастить:
    new WindowWithMethod((IBooleanStateEvents)_state);
    Теперь дело осталось за малым, нужно поменять значение из MainWindow, и отреагировать на него в WindowWithMethod:
    public class MainWindow : Window
    {
        private void HandleCheckboxValueChanged(object sender, EventArgs args)
        {
            _state.State = _checkBox.Checked;
        }
    }

    public class WindowWithMethod : Window
    {
        // .................
        public WindowWithMethod(IBooleanStateEvents stateEvents)
        {
            // ........................
            _stateEvents = stateEvents;
            _stateEvents.StateChanged += HandleStateChanged;
           // .........................
        }
    
        private void HandleStateChanged(object sender, EventArgs<bool> args)
        {
            Method(args.State);
        }
    }


    Так вам не придётся торчать наружу публичным методом из второго окна, и появится гораздо больше возможностей для дальнейших изменений. Если лениво - интерфейсы можно не определять и использовать только класс.
    Ответ написан
  • Почему игнорируется объемный фрагмент кода после выполнения httpClient.GetStreamAsync()?

    gdt
    @gdt
    Программист
    Я бы рекомендовал для начала завернуть ваш кусок кода в try/catch (Exception e), поставить брейкпоинт на следующей строчке после проблемного метода, и в теле catch. Либо там либо там должно сработать, так вы сузите круг подозреваемых :)
    Ответ написан
    Комментировать
  • Как убрать отступы текста в кнопке?

    gdt
    @gdt
    Программист
    В первую очередь в такой ситуации имеет смысл уменьшить Padding до 0 для всех четырёх сторон.
    Если этого недостаточно - тут Reduce Padding Around Text in WinForms Button собрано несколько вариантов решения вашей проблемы.
    Ответ написан
    Комментировать
  • Каким образом исправить системную ошибку PersistenceException?

    gdt
    @gdt
    Программист
    Я думаю что было бы полезно в первую очередь посмотреть на код внутри getParcelShops, ошибка явно идёт оттуда. Вообще перед тем, как задавать вопрос, очень полезно попробовать поискать информацию в вашем любимом поисковике:
    persistenceexception c#
    Первая ссылка - PersistenceException Class
    Написано:
    This exception is thrown by a SqlPersistenceProviderFactory when general connectivity errors are encountered.

    Таким образом, ваш svc где-то внутри себя так или иначе использует SqlPersistenceProviderFactory, и судя по всему испытывает какие-то проблемы с подключением к серверу. Проверьте ваш Connection String, далее если там всё верно, есть два основных варианта:
    • Сервер находится где-то в интернете, тогда у вас проблемы с firewall (либо на вашей либо на серверной стороне)
    • Сервер должен быть развёрнут локально - проверьте что он развернут и запущен, порт доступен для подключения, firewall не блокирует локальные подключения
    Ответ написан
    Комментировать
  • Как сделать уровни сложности для игры Угадай число C# Windows Forms?

    gdt
    @gdt
    Программист
    Смотрите, для того, чтобы угадать число, нужно его сначала загадать.
    Вы сами понимаете, чем различаются уровни сложности - а именно, диапазоном загадываемых значений.
    То есть, если подумать (никогда бы не подумал что над этим нужно думать) - вам нужно генерировать числа из разных диапазонов, в соответствии с уровнем сложности.
    Сначала нужно определиться, какие у вас будут уровни сложности - проще всего завести новый enum:
    enum Level
    {
        Easy,
        Normal,
        Hard,
    }


    Далее, вам необходимо как-то представлять свой диапазон. Можно сделать массив на два элемента, можно использовать кортеж, но мы создадим новую сущность под это дело:

    class Range
    {
        public Range(int min, int max)
        {
            Min = min;
            Max = max;
        }
    
        public int Min { get; }
        public int Max { get; }
    }


    Далее, нужно как-то связать наши уровни сложности и диапазоны. Тут не будем усложнять, пусть будет просто метод:

    private static Range GetRange(Level level)
    {
        switch (level)
        {
            case Level.Easy: return new Range(0, 10);
            case Level.Normal: return new Range(0, 50);
            case Level.Hard: return new Range(0, 100);
        }
    }


    Теперь осталось только сгенерировать случайное число, для этого вам нужен генератор случайных чисел, и метод, собственно генерирующий числа на основе уровней сложности.
    Добавляете в свой класс поле, помним о том, что Random непотокобезопасный (вряд ли это проблема в вашем случае, но знать надо):
    private static readonly Random = new Random();
    Добавляете метод, генерирующий числа:
    private static int GenerateNumber(Level level)
    {
        var range = GetRange(level);
        return Random.Next(range.Min, range.Max);
    }


    И там, где вы будете угадывать число, вызываете этот метод с желаемым уровнем сложности.

    Как видите, если подумать - ничего сложного тут нет, всё дело техники.
    Ответ написан
    Комментировать
  • Как передать DateTime из View в Controller?

    gdt
    @gdt
    Программист
    Может ли это чем-то помочь? https://www.youtube.com/watch?v=dsk4YyDEn4w
    Ответ написан
    Комментировать
  • Почему при сложении 0.001 типа float или doable 1000 раз через несколько нулей после запятой появляются ещё числа из ниоткуда и как это решить?

    gdt
    @gdt
    Программист
    И ни одного пояснения :)
    Если вам нужно, чтобы работало так, как вы ожидаете - воспользуйтесь замечательным советом Бобби Шифер .
    Если объяснить на пальцах - есть два способа хранить числа с точкой - fixed point (фиксированная точка) и floating point (плавающая точка). У себя в примере вы используете тип данных с плавающей точкой (неспроста он называется float, а double - это float с двойной точностью, только и всего). Грубо говоря, числа с плавающей точкой представляются так: M*10^E, т. е. в памяти два значения M и E просто следуют друг за другом. К сожалению, компьютеры используют двоичную систему счисления, и далеко не всегда то, что можно просто записать в десятичной системе счисления - настолько же просто записать в двоичной, и наоборот. С учётом того, что объём памяти, выделяемый под хранение мантиссы, ограничен - она округляется до ближайшего двоичного представления, что после перевода назад, в десятичную систему счисления, и даёт такой, на первый взгляд, контринтуитивный результат.
    Для разнообразия можете попробовать сложить очень маленькое и очень большое число.
    Ответ написан
    3 комментария
  • Как мне конвертировать binary в bytes []?

    gdt
    @gdt
    Программист
    Так сериализуйте не в FileStream а в MemoryStream, оттуда вытащить байты проще простого
    Ответ написан
  • Почему нет файла конфигурации app.config в проекте visual studio?

    gdt
    @gdt
    Программист
    На тот случай, если вам нужно быстрое решение - создайте файл, добавьте в него:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
    </configuration>


    Далее у себя в проекте (надеюсь вы используете SDK style project) в проперти group добавьте AppConfig, чтобы было примерно так (остальные свойства не нужно добавлять если их у вас нет):
    <PropertyGroup>
      <OutputType>WinExe</OutputType>
      <TargetFramework>net4.5</TargetFramework>
      <UseWPF>true</UseWPF>
      <AppConfig>App.config</AppConfig>
      <ApplicationManifest>App.manifest</ApplicationManifest>
      <Nullable>enable</Nullable>
    </PropertyGroup>


    Сам файл отдельно не нужно добавлять в проект, всякие None Include с CopyIfNewer не решают проблему, т. к. не меняют имя файла.
    Ответ написан
    Комментировать
  • Как сделать сканирование COM-портов и добавление в ComboBox?

    gdt
    @gdt
    Программист
    Вот здесь https://stackoverflow.com/a/1394301/1828989 перечислены все самые популярные способы обнаружения портов, выбирайте по вкусу :)
    Ответ написан
    Комментировать
  • Каким образом можно заставить программу отрисовывать объекты по порядку через определённый интервал времени?

    gdt
    @gdt
    Программист
    У вас проблема из-за того, что вы всё время замораживаете основной поток (который и должен всё отрисовывать). И делаете всё в конструкторе, когда форму ещё никто не показал даже.
    Попробуйте переделать ваш drawTPointElement так:
    public async Task drawTPointElement(TPoint _rectangle)
    {
        Canvas.SetLeft(_rectangle.getPoint(), _rectangle.getXCoord());
        Canvas.SetTop(_rectangle.getPoint(), _rectangle.getYCoord());
        await Task.Delay(1000);
        mainCanvas.Children.Add(_rectangle.getPoint());
    }


    А в Main завернуть цикл в Task.Run вот так:
    Task.Run(async () =>
    {
        for (int i = 0; i <=5; i++)
        {
            TPoint point = new TPoint(5, i, 1, Brushes.Red);
            await drawTPointElement(point);
        }
    });


    Единственное что у вас скорее всего с таким подходом будут ошибки из-за того, что добавление в Children может происходить из другого потока, для этого можно обернуть mainCanvas.Children.Add(_rectangle.getPoint()); в что-то по типу Dispatcher.Invoke
    Ответ написан
  • Почему ошибка появилась и как ее исправить?

    gdt
    @gdt
    Программист
    Вам нужно поместить слово Автомобиль в кавычки, точно так же как у вас сделано со столбцами.
    Ответ написан
  • Где ошибка в данном SQL-запросе?

    gdt
    @gdt
    Программист
    Выглядит так, как будто имя таблицы тоже необходимо заключить в кавычки.
    https://stackoverflow.com/q/2901453/1828989 вот тут больше информации и примеры.
    Ответ написан
    Комментировать
  • Как убрать async, если не нужон, но требует?

    gdt
    @gdt
    Программист
    Во-первых, используйте .GetAwaiter().GetResult() если вам нужно получить результат синхронно.
    Во-вторых, ваш дедлок это хрестоматийный пример, примерно как детский мат. Дело в том, что вы не указали .ConfigureAwait(false) в своём асинхронном вызове, это значит, что CLR будет ждать освобождения вызывающего потока, чтобы продолжить выполнять код после await. Однако вызывающий поток уже бесконечно занят ожиданием завершения вашего асинхронного метода там, где вы получаете Result - вот вам и типичный deadlock.
    Таким образом, вам нужно либо добавить .ConfigureAwait(false) к вашему асинхронному вызову (это приведет к необходимости выполнять дальнейшие изменения в UI через диспетчер, Dispatcher.Invoke в WPF), либо запустить свой код в контексте синхронизации, отличном от того, который используется в UI - самый простой способ это вообще не использовать контекст - выполнить свой код внутри Task.Run:
    Task.Run(async() => html = await browser.GetSourceAsync());

    Или
    private async Task<string> GetHTMLFromWebBrowser()
    {
        return await browser.GetSourceAsync();
    }
    
    ....
    
    Task.Run(async() => html = await GetHTMLFromWebBrowser());

    .ConfigureAwait() в таком случае не нужен, т. к. без контекста синхронизации он ничего не делает.
    Ответ написан
    Комментировать
  • Как написать юнит тест для ввода с клавиатуры?

    gdt
    @gdt
    Программист
    Если вы действительно хотите тестировать ввод с клавиатуры, это значит что вам нужно замокать статический метод.
    У Fody есть add-in Fody.Ionad, который позволяет делать как раз именно это.
    Но, конечно, будет правильнее воспользоваться советом предыдущих ответчиков, и переделать код так, чтобы он был более тестируем.
    Ответ написан
    Комментировать
  • Как обработать производный класс аргументов в делегате принимающем базовый класс аргументов?

    gdt
    @gdt
    Программист
    Я вижу два варианта - простой и правильный.
    Простой состоит в том, что все ваши методы будут иметь сигнатуры базового класса, и в каждом наследнике вы будете кастовать аргументы к нужному типу:
    if (args is ConcreteArgs concreteArgs)
    {
        // do something with concreteArgs
    }

    Это в целом не очень удобно, но просто и работает.

    Правильный (на мой взгляд) вариант состоит в том, чтобы использовать шаблон программирования "посетитель", вот на хабре есть статья где рассматривается вычисление площади различных фигур - https://habr.com/ru/post/332042/.

    Ещё есть вариант сделать класс generic, который принимает тип аргументов, и наложить констрейнт where T : FunctionArgs.
    Ответ написан
    Комментировать